From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871441855379.96293908342875; Mon, 6 Mar 2017 23:24:01 -0800 (PST) Received: from localhost ([::1]:47944 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9TU-0003ZJ-EW for importer@patchew.org; Tue, 07 Mar 2017 02:24:00 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44383) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QK-0001XM-9R for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:45 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QH-00067h-3S for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from mx1.redhat.com ([209.132.183.28]:42552) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QG-00067G-TR for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:41 -0500 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C1DE476E0 for ; Tue, 7 Mar 2017 07:20:40 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277Kdma016827 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:40 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id C1340113864A; Tue, 7 Mar 2017 08:20:37 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:14 +0100 Message-Id: <1488871237-12332-2-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Tue, 07 Mar 2017 07:20:40 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 01/24] test-qemu-opts: Cover qemu_opts_parse() of "no" X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" qemu_opts_parse() interprets "no" as negated empty key. Consistent with its acceptance of empty keys elsewhere, whatever that's worth. Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-2-git-send-email-armbru@redhat.com> --- tests/test-qemu-opts.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c index c46ef31..f6310b3 100644 --- a/tests/test-qemu-opts.c +++ b/tests/test-qemu-opts.c @@ -532,6 +532,11 @@ static void test_opts_parse(void) g_assert_cmpstr(qemu_opt_get(opts, "aus"), =3D=3D, "off"); g_assert_cmpstr(qemu_opt_get(opts, "noaus"), =3D=3D, ""); =20 + /* Implied value, negated empty key */ + opts =3D qemu_opts_parse(&opts_list_03, "no", false, &error_abort); + g_assert_cmpuint(opts_count(opts), =3D=3D, 1); + g_assert_cmpstr(qemu_opt_get(opts, ""), =3D=3D, "off"); + /* Implied key */ opts =3D qemu_opts_parse(&opts_list_03, "an,noaus,noaus=3D", true, &error_abort); --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871571280112.9531578418489; Mon, 6 Mar 2017 23:26:11 -0800 (PST) Received: from localhost ([::1]:47957 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9Va-0005WL-29 for importer@patchew.org; Tue, 07 Mar 2017 02:26:10 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44388) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QK-0001XP-AS for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:45 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QH-00067b-3D for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from mx1.redhat.com ([209.132.183.28]:38762) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QG-00067F-TL for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:41 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C5F58C030707 for ; Tue, 7 Mar 2017 07:20:40 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277KdVW016934 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:40 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id C3700113864D; Tue, 7 Mar 2017 08:20:37 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:15 +0100 Message-Id: <1488871237-12332-3-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Tue, 07 Mar 2017 07:20:40 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 02/24] tests: Fix gcov-files-test-qemu-opts-y, gcov-files-test-logging-y X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-3-git-send-email-armbru@redhat.com> --- tests/Makefile.include | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index ace4e80..b65c2b5 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -93,7 +93,7 @@ gcov-files-check-qom-interface-y =3D qom/object.c check-unit-y +=3D tests/check-qom-proplist$(EXESUF) gcov-files-check-qom-proplist-y =3D qom/object.c check-unit-y +=3D tests/test-qemu-opts$(EXESUF) -gcov-files-test-qemu-opts-y =3D qom/test-qemu-opts.c +gcov-files-test-qemu-opts-y =3D util/qemu-option.c check-unit-y +=3D tests/test-write-threshold$(EXESUF) gcov-files-test-write-threshold-y =3D block/write-threshold.c check-unit-y +=3D tests/test-crypto-hash$(EXESUF) @@ -118,8 +118,8 @@ check-unit-y +=3D tests/test-crypto-ivgen$(EXESUF) check-unit-y +=3D tests/test-crypto-afsplit$(EXESUF) check-unit-y +=3D tests/test-crypto-xts$(EXESUF) check-unit-y +=3D tests/test-crypto-block$(EXESUF) -gcov-files-test-logging-y =3D tests/test-logging.c check-unit-y +=3D tests/test-logging$(EXESUF) +gcov-files-test-logging-y =3D util/log.c check-unit-$(CONFIG_REPLICATION) +=3D tests/test-replication$(EXESUF) check-unit-y +=3D tests/test-bufferiszero$(EXESUF) gcov-files-check-bufferiszero-y =3D util/bufferiszero.c --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871575417133.78373872651707; Mon, 6 Mar 2017 23:26:15 -0800 (PST) Received: from localhost ([::1]:47958 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9Ve-0005XR-3j for importer@patchew.org; Tue, 07 Mar 2017 02:26:14 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44384) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QK-0001XN-9U for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QH-00067v-8Q for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from mx1.redhat.com ([209.132.183.28]:37372) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QG-00067N-Ud for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:41 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 29F9C81222 for ; Tue, 7 Mar 2017 07:20:41 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277Kd1F016263 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:40 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id C6D9D1138650; Tue, 7 Mar 2017 08:20:37 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:16 +0100 Message-Id: <1488871237-12332-4-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Tue, 07 Mar 2017 07:20:41 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 03/24] keyval: New keyval_parse() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" keyval_parse() parses KEY=3DVALUE,... into a QDict. Works like qemu_opts_parse(), except: * Returns a QDict instead of a QemuOpts (d'oh). * Supports nesting, unlike QemuOpts: a KEY is split into key fragments at '.' (dotted key convention; the block layer does something similar on top of QemuOpts). The key fragments are QDict keys, and the last one's value is updated to VALUE. * Each key fragment may be up to 127 bytes long. qemu_opts_parse() limits the entire key to 127 bytes. * Overlong key fragments are rejected. qemu_opts_parse() silently truncates them. * Empty key fragments are rejected. qemu_opts_parse() happily accepts empty keys. * It does not store the returned value. qemu_opts_parse() stores it in the QemuOptsList. * It does not treat parameter "id" specially. qemu_opts_parse() ignores all but the first "id", and fails when its value isn't id_wellformed(), or duplicate (a QemuOpts with the same ID is already stored). It also screws up when a value contains ",id=3D". * Implied value is not supported. qemu_opts_parse() desugars "foo" to "foo=3Don", and "nofoo" to "foo=3Doff". * An implied key's value can't be empty, and can't contain ','. I intend to grow this into a saner replacement for QemuOpts. It'll take time, though. Note: keyval_parse() provides no way to do lists, and its key syntax is incompatible with the __RFQDN_ prefix convention for downstream extensions, because it blindly splits at '.', even in __RFQDN_. Both issues will be addressed later in the series. Signed-off-by: Markus Armbruster Message-Id: <1488317230-26248-4-git-send-email-armbru@redhat.com> --- include/qemu/option.h | 3 + tests/.gitignore | 1 + tests/Makefile.include | 3 + tests/test-keyval.c | 180 ++++++++++++++++++++++++++++++++++++++ util/Makefile.objs | 1 + util/keyval.c | 231 +++++++++++++++++++++++++++++++++++++++++++++= ++++ 6 files changed, 419 insertions(+) create mode 100644 tests/test-keyval.c create mode 100644 util/keyval.c diff --git a/include/qemu/option.h b/include/qemu/option.h index e786df0..f7338db 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -141,4 +141,7 @@ void qemu_opts_print_help(QemuOptsList *list); void qemu_opts_free(QemuOptsList *list); QemuOptsList *qemu_opts_append(QemuOptsList *dst, QemuOptsList *list); =20 +QDict *keyval_parse(const char *params, const char *implied_key, + Error **errp); + #endif diff --git a/tests/.gitignore b/tests/.gitignore index dc37519..30b7740 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -47,6 +47,7 @@ test-io-channel-file.txt test-io-channel-socket test-io-channel-tls test-io-task +test-keyval test-logging test-mul64 test-opts-visitor diff --git a/tests/Makefile.include b/tests/Makefile.include index b65c2b5..3c34295 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -94,6 +94,8 @@ check-unit-y +=3D tests/check-qom-proplist$(EXESUF) gcov-files-check-qom-proplist-y =3D qom/object.c check-unit-y +=3D tests/test-qemu-opts$(EXESUF) gcov-files-test-qemu-opts-y =3D util/qemu-option.c +check-unit-y +=3D tests/test-keyval$(EXESUF) +gcov-files-test-keyval-y =3D util/keyval.c check-unit-y +=3D tests/test-write-threshold$(EXESUF) gcov-files-test-write-threshold-y =3D block/write-threshold.c check-unit-y +=3D tests/test-crypto-hash$(EXESUF) @@ -720,6 +722,7 @@ tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o= $(test-util-obj-y) \ $(chardev-obj-y) tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_s= cm_helper.o 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-write-threshold$(EXESUF): tests/test-write-threshold.o $(test-b= lock-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) diff --git a/tests/test-keyval.c b/tests/test-keyval.c new file mode 100644 index 0000000..27f6625 --- /dev/null +++ b/tests/test-keyval.c @@ -0,0 +1,180 @@ +/* + * Unit tests for parsing of KEY=3DVALUE,... strings + * + * Copyright (C) 2017 Red Hat Inc. + * + * Authors: + * Markus Armbruster , + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/option.h" + +static void test_keyval_parse(void) +{ + Error *err =3D NULL; + QDict *qdict, *sub_qdict; + char long_key[129]; + char *params; + + /* Nothing */ + qdict =3D keyval_parse("", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), =3D=3D, 0); + QDECREF(qdict); + + /* Empty key (qemu_opts_parse() accepts this) */ + qdict =3D keyval_parse("=3Dval", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Empty key fragment */ + qdict =3D keyval_parse(".", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + qdict =3D keyval_parse("key.", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Overlong key */ + memset(long_key, 'a', 127); + long_key[127] =3D 'z'; + long_key[128] =3D 0; + params =3D g_strdup_printf("k.%s=3Dv", long_key); + qdict =3D keyval_parse(params + 2, NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Overlong key fragment */ + qdict =3D keyval_parse(params, NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + g_free(params); + + /* Long key (qemu_opts_parse() accepts and truncates silently) */ + params =3D g_strdup_printf("k.%s=3Dv", long_key + 1); + qdict =3D keyval_parse(params + 2, NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), =3D=3D, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, long_key + 1), =3D=3D, "v"); + QDECREF(qdict); + + /* Long key fragment */ + qdict =3D keyval_parse(params, NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), =3D=3D, 1); + sub_qdict =3D qdict_get_qdict(qdict, "k"); + g_assert(sub_qdict); + g_assert_cmpuint(qdict_size(sub_qdict), =3D=3D, 1); + g_assert_cmpstr(qdict_get_try_str(sub_qdict, long_key + 1), =3D=3D, "v= "); + QDECREF(qdict); + g_free(params); + + /* Multiple keys, last one wins */ + qdict =3D keyval_parse("a=3D1,b=3D2,,x,a=3D3", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), =3D=3D, 2); + g_assert_cmpstr(qdict_get_try_str(qdict, "a"), =3D=3D, "3"); + g_assert_cmpstr(qdict_get_try_str(qdict, "b"), =3D=3D, "2,x"); + QDECREF(qdict); + + /* Even when it doesn't in qemu_opts_parse() */ + qdict =3D keyval_parse("id=3Dfoo,id=3Dbar", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), =3D=3D, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, "id"), =3D=3D, "bar"); + QDECREF(qdict); + + /* Dotted keys */ + qdict =3D keyval_parse("a.b.c=3D1,a.b.c=3D2,d=3D3", NULL, &error_abort= ); + g_assert_cmpuint(qdict_size(qdict), =3D=3D, 2); + sub_qdict =3D qdict_get_qdict(qdict, "a"); + g_assert(sub_qdict); + g_assert_cmpuint(qdict_size(sub_qdict), =3D=3D, 1); + sub_qdict =3D qdict_get_qdict(sub_qdict, "b"); + g_assert(sub_qdict); + g_assert_cmpuint(qdict_size(sub_qdict), =3D=3D, 1); + g_assert_cmpstr(qdict_get_try_str(sub_qdict, "c"), =3D=3D, "2"); + g_assert_cmpstr(qdict_get_try_str(qdict, "d"), =3D=3D, "3"); + QDECREF(qdict); + + /* Inconsistent dotted keys */ + qdict =3D keyval_parse("a.b=3D1,a=3D2", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + qdict =3D keyval_parse("a.b=3D1,a.b.c=3D2", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Trailing comma is ignored */ + qdict =3D keyval_parse("x=3Dy,", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), =3D=3D, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, "x"), =3D=3D, "y"); + QDECREF(qdict); + + /* Except when it isn't */ + qdict =3D keyval_parse(",", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Value containing ,id=3D not misinterpreted as qemu_opts_parse() doe= s */ + qdict =3D keyval_parse("x=3D,,id=3Dbar", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), =3D=3D, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, "x"), =3D=3D, ",id=3Dbar"); + QDECREF(qdict); + + /* Anti-social ID is left to caller (qemu_opts_parse() rejects it) */ + qdict =3D keyval_parse("id=3D666", NULL, &error_abort); + g_assert_cmpuint(qdict_size(qdict), =3D=3D, 1); + g_assert_cmpstr(qdict_get_try_str(qdict, "id"), =3D=3D, "666"); + QDECREF(qdict); + + /* Implied value not supported (unlike qemu_opts_parse()) */ + qdict =3D keyval_parse("an,noaus,noaus=3D", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Implied value, key "no" (qemu_opts_parse(): negated empty key) */ + qdict =3D keyval_parse("no", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Implied key */ + qdict =3D keyval_parse("an,aus=3Doff,noaus=3D", "implied", &error_abor= t); + g_assert_cmpuint(qdict_size(qdict), =3D=3D, 3); + g_assert_cmpstr(qdict_get_try_str(qdict, "implied"), =3D=3D, "an"); + g_assert_cmpstr(qdict_get_try_str(qdict, "aus"), =3D=3D, "off"); + g_assert_cmpstr(qdict_get_try_str(qdict, "noaus"), =3D=3D, ""); + QDECREF(qdict); + + /* Implied dotted key */ + qdict =3D keyval_parse("val", "eins.zwei", &error_abort); + g_assert_cmpuint(qdict_size(qdict), =3D=3D, 1); + sub_qdict =3D qdict_get_qdict(qdict, "eins"); + g_assert(sub_qdict); + g_assert_cmpuint(qdict_size(sub_qdict), =3D=3D, 1); + g_assert_cmpstr(qdict_get_try_str(sub_qdict, "zwei"), =3D=3D, "val"); + QDECREF(qdict); + + /* Implied key with empty value (qemu_opts_parse() accepts this) */ + qdict =3D keyval_parse(",", "implied", &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Likewise (qemu_opts_parse(): implied key with comma value) */ + qdict =3D keyval_parse(",,,a=3D1", "implied", &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Empty key is not an implied key */ + qdict =3D keyval_parse("=3Dval", "implied", &err); + error_free_or_abort(&err); + g_assert(!qdict); +} + +int main(int argc, char *argv[]) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/keyval/keyval_parse", test_keyval_parse); + g_test_run(); + return 0; +} diff --git a/util/Makefile.objs b/util/Makefile.objs index bc629e2..06366b5 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -24,6 +24,7 @@ util-obj-y +=3D error.o qemu-error.o util-obj-y +=3D id.o util-obj-y +=3D iov.o qemu-config.o qemu-sockets.o uri.o notify.o util-obj-y +=3D qemu-option.o qemu-progress.o +util-obj-y +=3D keyval.o util-obj-y +=3D hexdump.o util-obj-y +=3D crc32c.o util-obj-y +=3D uuid.o diff --git a/util/keyval.c b/util/keyval.c new file mode 100644 index 0000000..990126f --- /dev/null +++ b/util/keyval.c @@ -0,0 +1,231 @@ +/* + * Parsing KEY=3DVALUE,... strings + * + * Copyright (C) 2017 Red Hat Inc. + * + * Authors: + * Markus Armbruster , + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +/* + * KEY=3DVALUE,... syntax: + * + * key-vals =3D [ key-val { ',' key-val } [ ',' ] ] + * key-val =3D key '=3D' val + * key =3D key-fragment { '.' key-fragment } + * key-fragment =3D / [^=3D,.]* / + * val =3D { / [^,]* / | ',,' } + * + * Semantics defined by reduction to JSON: + * + * key-vals defines a tree of objects rooted at R + * where for each key-val =3D key-fragment . ... =3D val in key-vals + * R op key-fragment op ... =3D val' + * where (left-associative) op is member reference L.key-fragment + * val' is val with ',,' replaced by ',' + * and only R may be empty. + * + * Duplicate keys are permitted; all but the last one are ignored. + * + * The equations must have a solution. Counter-example: a.b=3D1,a=3D2 + * doesn't have one, because R.a must be an object to satisfy a.b=3D1 + * and a string to satisfy a=3D2. + * + * The length of any key-fragment must be between 1 and 127. + * + * Design flaw: there is no way to denote an empty non-root object. + * While interpreting "key absent" as empty object seems natural + * (removing a key-val from the input string removes the member when + * there are more, so why not when it's the last), it doesn't work: + * "key absent" already means "optional object absent", which isn't + * the same as "empty object present". + * + * Additional syntax for use with an implied key: + * + * key-vals-ik =3D val-no-key [ ',' key-vals ] + * val-no-key =3D / [^=3D,]* / + * + * where no-key is syntactic sugar for implied-key=3Dval-no-key. + * + * TODO support lists + * TODO support key-fragment with __RFQDN_ prefix (downstream extensions) + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qmp/qstring.h" +#include "qemu/option.h" + +/* + * Ensure @cur maps @key_in_cur the right way. + * If @value is null, it needs to map to a QDict, else to this + * QString. + * If @cur doesn't have @key_in_cur, put an empty QDict or @value, + * respectively. + * Else, if it needs to map to a QDict, and already does, do nothing. + * Else, if it needs to map to this QString, and already maps to a + * QString, replace it by @value. + * Else, fail because we have conflicting needs on how to map + * @key_in_cur. + * In any case, take over the reference to @value, i.e. if the caller + * wants to hold on to a reference, it needs to QINCREF(). + * Use @key up to @key_cursor to identify the key in error messages. + * On success, return the mapped value. + * On failure, store an error through @errp and return NULL. + */ +static QObject *keyval_parse_put(QDict *cur, + const char *key_in_cur, QString *value, + const char *key, const char *key_cursor, + Error **errp) +{ + QObject *old, *new; + + old =3D qdict_get(cur, key_in_cur); + if (old) { + if (qobject_type(old) !=3D (value ? QTYPE_QSTRING : QTYPE_QDICT)) { + error_setg(errp, "Parameters '%.*s.*' used inconsistently", + (int)(key_cursor - key), key); + QDECREF(value); + return NULL; + } + if (!value) { + return old; /* already QDict, do nothing */ + } + new =3D QOBJECT(value); /* replacement */ + } else { + new =3D QOBJECT(value) ?: QOBJECT(qdict_new()); + } + qdict_put_obj(cur, key_in_cur, new); + return new; +} + +/* + * Parse one KEY=3DVALUE from @params, store result in @qdict. + * The first fragment of KEY applies to @qdict. Subsequent fragments + * apply to nested QDicts, which are created on demand. @implied_key + * is as in keyval_parse(). + * On success, return a pointer to the next KEY=3DVALUE, or else to '\0'. + * On failure, return NULL. + */ +static const char *keyval_parse_one(QDict *qdict, const char *params, + const char *implied_key, + Error **errp) +{ + const char *key, *key_end, *s; + size_t len; + char key_in_cur[128]; + QDict *cur; + QObject *next; + QString *val; + + key =3D params; + len =3D strcspn(params, "=3D,"); + if (implied_key && len && key[len] !=3D '=3D') { + /* Desugar implied key */ + key =3D implied_key; + len =3D strlen(implied_key); + } + key_end =3D key + len; + + /* + * Loop over key fragments: @s points to current fragment, it + * applies to @cur. @key_in_cur[] holds the previous fragment. + */ + cur =3D qdict; + s =3D key; + for (;;) { + for (len =3D 0; s + len < key_end && s[len] !=3D '.'; len++) { + } + if (!len) { + assert(key !=3D implied_key); + error_setg(errp, "Invalid parameter '%.*s'", + (int)(key_end - key), key); + return NULL; + } + if (len >=3D sizeof(key_in_cur)) { + assert(key !=3D implied_key); + error_setg(errp, "Parameter%s '%.*s' is too long", + s !=3D key || s + len !=3D key_end ? " fragment" : = "", + (int)len, s); + return NULL; + } + + if (s !=3D key) { + next =3D keyval_parse_put(cur, key_in_cur, NULL, + key, s - 1, errp); + if (!next) { + return NULL; + } + cur =3D qobject_to_qdict(next); + assert(cur); + } + + memcpy(key_in_cur, s, len); + key_in_cur[len] =3D 0; + s +=3D len; + + if (*s !=3D '.') { + break; + } + s++; + } + + if (key =3D=3D implied_key) { + assert(!*s); + s =3D params; + } else { + if (*s !=3D '=3D') { + error_setg(errp, "Expected '=3D' after parameter '%.*s'", + (int)(s - key), key); + return NULL; + } + s++; + } + + val =3D qstring_new(); + for (;;) { + if (!*s) { + break; + } else if (*s =3D=3D ',') { + s++; + if (*s !=3D ',') { + break; + } + } + qstring_append_chr(val, *s++); + } + + if (!keyval_parse_put(cur, key_in_cur, val, key, key_end, errp)) { + return NULL; + } + return s; +} + +/* + * Parse @params in QEMU's traditional KEY=3DVALUE,... syntax. + * If @implied_key, the first KEY=3D can be omitted. @implied_key is + * implied then, and VALUE can't be empty or contain ',' or '=3D'. + * On success, return a dictionary of the parsed keys and values. + * On failure, store an error through @errp and return NULL. + */ +QDict *keyval_parse(const char *params, const char *implied_key, + Error **errp) +{ + QDict *qdict =3D qdict_new(); + const char *s; + + s =3D params; + while (*s) { + s =3D keyval_parse_one(qdict, s, implied_key, errp); + if (!s) { + QDECREF(qdict); + return NULL; + } + implied_key =3D NULL; + } + + return qdict; +} --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871938066118.91035395218353; Mon, 6 Mar 2017 23:32:18 -0800 (PST) Received: from localhost ([::1]:47987 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9bU-0002QQ-Co for importer@patchew.org; Tue, 07 Mar 2017 02:32:16 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44391) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QK-0001XQ-BZ for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QH-000680-9N for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from mx1.redhat.com ([209.132.183.28]:33668) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QG-00067O-Vw for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:41 -0500 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 34AB97F081 for ; Tue, 7 Mar 2017 07:20:41 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277KdxC024157 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Tue, 7 Mar 2017 02:20:40 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id CA1861138657; Tue, 7 Mar 2017 08:20:37 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:17 +0100 Message-Id: <1488871237-12332-5-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Tue, 07 Mar 2017 07:20:41 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 04/24] qapi: qobject input visitor variant for use with keyval_parse() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: "Daniel P. Berrange" Currently the QObjectInputVisitor assumes that all scalar values are directly represented as the final types declared by the thing being visited. i.e. it assumes an 'int' is using QInt, and a 'bool' is using QBool, etc. This is good when QObjectInputVisitor is fed a QObject that came from a JSON document on the QMP monitor, as it will strictly validate correctness. To allow QObjectInputVisitor to be reused for visiting a QObject originating from keyval_parse(), an alternative mode is needed where all the scalars types are represented as QString and converted on the fly to the final desired type. Signed-off-by: Daniel P. Berrange Message-Id: <1475246744-29302-8-git-send-email-berrange@redhat.com> Rebased, conflicts resolved, commit message updated to refer to keyval_parse(). autocast replaced by keyval in identifiers, noautocast replaced by fail in tests. Fix qobject_input_type_uint64_keyval() not to reject '-', for QemuOpts compatibility: replace parse_uint_full() by open-coded parse_option_number(). The next commit will add suitable tests. Leave out the fancy ERANGE error reporting for now, but add a TODO comment. Add it qobject_input_type_int64_keyval() and qobject_input_type_number_keyval(), too. Open code parse_option_bool() and parse_option_size() so we have to call qobject_input_get_name() only when actually needed. Again, leave out ERANGE error reporting for now. QAPI/QMP downstream extension prefixes __RFQDN_ don't work, because keyval_parse() splits them at '.'. This will be addressed later in the series. qobject_input_type_int64_keyval(), qobject_input_type_uint64_keyval(), qobject_input_type_number_keyval() tweaked for style. Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-5-git-send-email-armbru@redhat.com> --- include/qapi/qobject-input-visitor.h | 9 ++ qapi/qobject-input-visitor.c | 166 ++++++++++++++++++++++++++++++- tests/test-qobject-input-visitor.c | 188 +++++++++++++++++++++++++++++++= +++- 3 files changed, 358 insertions(+), 5 deletions(-) diff --git a/include/qapi/qobject-input-visitor.h b/include/qapi/qobject-in= put-visitor.h index 0b7633a..282f9d2 100644 --- a/include/qapi/qobject-input-visitor.h +++ b/include/qapi/qobject-input-visitor.h @@ -59,4 +59,13 @@ typedef struct QObjectInputVisitor QObjectInputVisitor; */ Visitor *qobject_input_visitor_new(QObject *obj); =20 +/* + * Create a QObject input visitor for @obj for use with keyval_parse() + * + * This is like qobject_input_visitor_new(), except scalars are all + * QString, and error messages refer to parts of @obj in the syntax + * keyval_parse() uses for KEYs. + */ +Visitor *qobject_input_visitor_new_keyval(QObject *obj); + #endif diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c index d192727..e2e3e70 100644 --- a/qapi/qobject-input-visitor.c +++ b/qapi/qobject-input-visitor.c @@ -1,7 +1,7 @@ /* * Input Visitor * - * Copyright (C) 2012-2016 Red Hat, Inc. + * Copyright (C) 2012-2017 Red Hat, Inc. * Copyright IBM, Corp. 2011 * * Authors: @@ -20,6 +20,7 @@ #include "qemu-common.h" #include "qapi/qmp/types.h" #include "qapi/qmp/qerror.h" +#include "qemu/cutils.h" =20 typedef struct StackObject { const char *name; /* Name of @obj in its parent, if any */ @@ -337,6 +338,31 @@ static void qobject_input_type_int64(Visitor *v, const= char *name, int64_t *obj, *obj =3D qint_get_int(qint); } =20 + +static void qobject_input_type_int64_keyval(Visitor *v, const char *name, + int64_t *obj, Error **errp) +{ + QObjectInputVisitor *qiv =3D to_qiv(v); + QObject *qobj =3D qobject_input_get_object(qiv, name, true, errp); + QString *qstr; + + if (!qobj) { + return; + } + qstr =3D qobject_to_qstring(qobj); + if (!qstr) { + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "string"); + return; + } + + if (qemu_strtoi64(qstring_get_str(qstr), NULL, 0, obj) < 0) { + /* TODO report -ERANGE more nicely */ + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + full_name(qiv, name), "integer"); + } +} + static void qobject_input_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) { @@ -358,6 +384,30 @@ static void qobject_input_type_uint64(Visitor *v, cons= t char *name, *obj =3D qint_get_int(qint); } =20 +static void qobject_input_type_uint64_keyval(Visitor *v, const char *name, + uint64_t *obj, Error **errp) +{ + QObjectInputVisitor *qiv =3D to_qiv(v); + QObject *qobj =3D qobject_input_get_object(qiv, name, true, errp); + QString *qstr; + + if (!qobj) { + return; + } + qstr =3D qobject_to_qstring(qobj); + if (!qstr) { + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "string"); + return; + } + + if (qemu_strtou64(qstring_get_str(qstr), NULL, 0, obj) < 0) { + /* TODO report -ERANGE more nicely */ + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + full_name(qiv, name), "integer"); + } +} + static void qobject_input_type_bool(Visitor *v, const char *name, bool *ob= j, Error **errp) { @@ -378,6 +428,35 @@ static void qobject_input_type_bool(Visitor *v, const = char *name, bool *obj, *obj =3D qbool_get_bool(qbool); } =20 +static void qobject_input_type_bool_keyval(Visitor *v, const char *name, + bool *obj, Error **errp) +{ + QObjectInputVisitor *qiv =3D to_qiv(v); + QObject *qobj =3D qobject_input_get_object(qiv, name, true, errp); + QString *qstr; + const char *str; + + if (!qobj) { + return; + } + qstr =3D qobject_to_qstring(qobj); + if (!qstr) { + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "string"); + return; + } + + str =3D qstring_get_str(qstr); + if (!strcmp(str, "on")) { + *obj =3D true; + } else if (!strcmp(str, "off")) { + *obj =3D false; + } else { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + full_name(qiv, name), "'on' or 'off'"); + } +} + static void qobject_input_type_str(Visitor *v, const char *name, char **ob= j, Error **errp) { @@ -426,6 +505,35 @@ static void qobject_input_type_number(Visitor *v, cons= t char *name, double *obj, full_name(qiv, name), "number"); } =20 +static void qobject_input_type_number_keyval(Visitor *v, const char *name, + double *obj, Error **errp) +{ + QObjectInputVisitor *qiv =3D to_qiv(v); + QObject *qobj =3D qobject_input_get_object(qiv, name, true, errp); + QString *qstr; + const char *str; + char *endp; + + if (!qobj) { + return; + } + qstr =3D qobject_to_qstring(qobj); + if (!qstr) { + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "string"); + return; + } + + str =3D qstring_get_str(qstr); + errno =3D 0; + *obj =3D strtod(str, &endp); + if (errno || endp =3D=3D str || *endp) { + /* TODO report -ERANGE more nicely */ + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "number"); + } +} + static void qobject_input_type_any(Visitor *v, const char *name, QObject *= *obj, Error **errp) { @@ -456,6 +564,30 @@ static void qobject_input_type_null(Visitor *v, const = char *name, Error **errp) } } =20 +static void qobject_input_type_size_keyval(Visitor *v, const char *name, + uint64_t *obj, Error **errp) +{ + QObjectInputVisitor *qiv =3D to_qiv(v); + QObject *qobj =3D qobject_input_get_object(qiv, name, true, errp); + QString *qstr; + + if (!qobj) { + return; + } + qstr =3D qobject_to_qstring(qobj); + if (!qstr) { + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "string"); + return; + } + + if (qemu_strtosz(qstring_get_str(qstr), NULL, obj) < 0) { + /* TODO report -ERANGE more nicely */ + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + full_name(qiv, name), "size"); + } +} + static void qobject_input_optional(Visitor *v, const char *name, bool *pre= sent) { QObjectInputVisitor *qiv =3D to_qiv(v); @@ -518,3 +650,35 @@ Visitor *qobject_input_visitor_new(QObject *obj) =20 return &v->visitor; } + +Visitor *qobject_input_visitor_new_keyval(QObject *obj) +{ + QObjectInputVisitor *v; + + v =3D g_malloc0(sizeof(*v)); + + v->visitor.type =3D VISITOR_INPUT; + v->visitor.start_struct =3D qobject_input_start_struct; + v->visitor.check_struct =3D qobject_input_check_struct; + v->visitor.end_struct =3D qobject_input_pop; + v->visitor.start_list =3D qobject_input_start_list; + v->visitor.next_list =3D qobject_input_next_list; + v->visitor.check_list =3D qobject_input_check_list; + v->visitor.end_list =3D qobject_input_pop; + v->visitor.start_alternate =3D qobject_input_start_alternate; + v->visitor.type_int64 =3D qobject_input_type_int64_keyval; + v->visitor.type_uint64 =3D qobject_input_type_uint64_keyval; + v->visitor.type_bool =3D qobject_input_type_bool_keyval; + v->visitor.type_str =3D qobject_input_type_str; + v->visitor.type_number =3D qobject_input_type_number_keyval; + v->visitor.type_any =3D qobject_input_type_any; + v->visitor.type_null =3D qobject_input_type_null; + v->visitor.type_size =3D qobject_input_type_size_keyval; + v->visitor.optional =3D qobject_input_optional; + v->visitor.free =3D qobject_input_free; + + v->root =3D obj; + qobject_incref(obj); + + return &v->visitor; +} diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-= visitor.c index 94305f5..32ba492 100644 --- a/tests/test-qobject-input-visitor.c +++ b/tests/test-qobject-input-visitor.c @@ -45,6 +45,7 @@ static void visitor_input_teardown(TestInputVisitorData *= data, function so that the JSON string used by the tests are kept in the test functions (and not in main()). */ static Visitor *visitor_input_test_init_internal(TestInputVisitorData *dat= a, + bool keyval, const char *json_string, va_list *ap) { @@ -53,11 +54,29 @@ static Visitor *visitor_input_test_init_internal(TestIn= putVisitorData *data, data->obj =3D qobject_from_jsonv(json_string, ap); g_assert(data->obj); =20 - data->qiv =3D qobject_input_visitor_new(data->obj); + if (keyval) { + data->qiv =3D qobject_input_visitor_new_keyval(data->obj); + } else { + data->qiv =3D qobject_input_visitor_new(data->obj); + } g_assert(data->qiv); return data->qiv; } =20 +static GCC_FMT_ATTR(3, 4) +Visitor *visitor_input_test_init_full(TestInputVisitorData *data, + bool keyval, + const char *json_string, ...) +{ + Visitor *v; + va_list ap; + + va_start(ap, json_string); + v =3D visitor_input_test_init_internal(data, keyval, json_string, &ap); + va_end(ap); + return v; +} + static GCC_FMT_ATTR(2, 3) Visitor *visitor_input_test_init(TestInputVisitorData *data, const char *json_string, ...) @@ -66,7 +85,7 @@ Visitor *visitor_input_test_init(TestInputVisitorData *da= ta, va_list ap; =20 va_start(ap, json_string); - v =3D visitor_input_test_init_internal(data, json_string, &ap); + v =3D visitor_input_test_init_internal(data, false, json_string, &ap); va_end(ap); return v; } @@ -81,7 +100,7 @@ Visitor *visitor_input_test_init(TestInputVisitorData *d= ata, static Visitor *visitor_input_test_init_raw(TestInputVisitorData *data, const char *json_string) { - return visitor_input_test_init_internal(data, json_string, NULL); + return visitor_input_test_init_internal(data, false, json_string, NULL= ); } =20 static void test_visitor_in_int(TestInputVisitorData *data, @@ -114,6 +133,43 @@ static void test_visitor_in_int_overflow(TestInputVisi= torData *data, error_free_or_abort(&err); } =20 +static void test_visitor_in_int_keyval(TestInputVisitorData *data, + const void *unused) +{ + int64_t res =3D 0, value =3D -42; + Error *err =3D NULL; + Visitor *v; + + v =3D visitor_input_test_init_full(data, true, "%" PRId64, value); + visit_type_int(v, NULL, &res, &err); + error_free_or_abort(&err); +} + +static void test_visitor_in_int_str_keyval(TestInputVisitorData *data, + const void *unused) +{ + int64_t res =3D 0, value =3D -42; + Visitor *v; + + v =3D visitor_input_test_init_full(data, true, "\"-42\""); + + visit_type_int(v, NULL, &res, &error_abort); + g_assert_cmpint(res, =3D=3D, value); +} + +static void test_visitor_in_int_str_fail(TestInputVisitorData *data, + const void *unused) +{ + int64_t res =3D 0; + Visitor *v; + Error *err =3D NULL; + + v =3D visitor_input_test_init(data, "\"-42\""); + + visit_type_int(v, NULL, &res, &err); + error_free_or_abort(&err); +} + static void test_visitor_in_bool(TestInputVisitorData *data, const void *unused) { @@ -126,6 +182,44 @@ static void test_visitor_in_bool(TestInputVisitorData = *data, g_assert_cmpint(res, =3D=3D, true); } =20 +static void test_visitor_in_bool_keyval(TestInputVisitorData *data, + const void *unused) +{ + bool res =3D false; + Error *err =3D NULL; + Visitor *v; + + v =3D visitor_input_test_init_full(data, true, "true"); + + visit_type_bool(v, NULL, &res, &err); + error_free_or_abort(&err); +} + +static void test_visitor_in_bool_str_keyval(TestInputVisitorData *data, + const void *unused) +{ + bool res =3D false; + Visitor *v; + + v =3D visitor_input_test_init_full(data, true, "\"on\""); + + visit_type_bool(v, NULL, &res, &error_abort); + g_assert_cmpint(res, =3D=3D, true); +} + +static void test_visitor_in_bool_str_fail(TestInputVisitorData *data, + const void *unused) +{ + bool res =3D false; + Visitor *v; + Error *err =3D NULL; + + v =3D visitor_input_test_init(data, "\"true\""); + + visit_type_bool(v, NULL, &res, &err); + error_free_or_abort(&err); +} + static void test_visitor_in_number(TestInputVisitorData *data, const void *unused) { @@ -138,6 +232,69 @@ static void test_visitor_in_number(TestInputVisitorDat= a *data, g_assert_cmpfloat(res, =3D=3D, value); } =20 +static void test_visitor_in_number_keyval(TestInputVisitorData *data, + const void *unused) +{ + double res =3D 0, value =3D 3.14; + Error *err =3D NULL; + Visitor *v; + + v =3D visitor_input_test_init_full(data, true, "%f", value); + + visit_type_number(v, NULL, &res, &err); + error_free_or_abort(&err); +} + +static void test_visitor_in_number_str_keyval(TestInputVisitorData *data, + const void *unused) +{ + double res =3D 0, value =3D 3.14; + Visitor *v; + + v =3D visitor_input_test_init_full(data, true, "\"3.14\""); + + visit_type_number(v, NULL, &res, &error_abort); + g_assert_cmpfloat(res, =3D=3D, value); +} + +static void test_visitor_in_number_str_fail(TestInputVisitorData *data, + const void *unused) +{ + double res =3D 0; + Visitor *v; + Error *err =3D NULL; + + v =3D visitor_input_test_init(data, "\"3.14\""); + + visit_type_number(v, NULL, &res, &err); + error_free_or_abort(&err); +} + +static void test_visitor_in_size_str_keyval(TestInputVisitorData *data, + const void *unused) +{ + uint64_t res, value =3D 500 * 1024 * 1024; + Visitor *v; + + v =3D visitor_input_test_init_full(data, true, "\"500M\""); + + visit_type_size(v, NULL, &res, &error_abort); + g_assert_cmpfloat(res, =3D=3D, value); +} + +static void test_visitor_in_size_str_fail(TestInputVisitorData *data, + const void *unused) +{ + uint64_t res =3D 0; + Visitor *v; + Error *err =3D NULL; + + v =3D visitor_input_test_init(data, "\"500M\""); + + visit_type_size(v, NULL, &res, &err); + error_free_or_abort(&err); +} + static void test_visitor_in_string(TestInputVisitorData *data, const void *unused) { @@ -294,7 +451,8 @@ static void test_visitor_in_null(TestInputVisitorData *= data, * when input is not null. */ =20 - v =3D visitor_input_test_init(data, "{ 'a': null, 'b': '', 'c': null }= "); + v =3D visitor_input_test_init_full(data, false, + "{ 'a': null, 'b': '' }"); visit_start_struct(v, NULL, NULL, 0, &error_abort); visit_type_null(v, "a", &error_abort); visit_type_null(v, "b", &err); @@ -1069,10 +1227,32 @@ int main(int argc, char **argv) NULL, test_visitor_in_int); input_visitor_test_add("/visitor/input/int_overflow", NULL, test_visitor_in_int_overflow); + input_visitor_test_add("/visitor/input/int_keyval", + NULL, test_visitor_in_int_keyval); + input_visitor_test_add("/visitor/input/int_str_keyval", + NULL, test_visitor_in_int_str_keyval); + input_visitor_test_add("/visitor/input/int_str_fail", + NULL, test_visitor_in_int_str_fail); input_visitor_test_add("/visitor/input/bool", NULL, test_visitor_in_bool); + input_visitor_test_add("/visitor/input/bool_keyval", + NULL, test_visitor_in_bool_keyval); + input_visitor_test_add("/visitor/input/bool_str_keyval", + NULL, test_visitor_in_bool_str_keyval); + input_visitor_test_add("/visitor/input/bool_str_fail", + NULL, test_visitor_in_bool_str_fail); input_visitor_test_add("/visitor/input/number", NULL, test_visitor_in_number); + input_visitor_test_add("/visitor/input/number_keyval", + NULL, test_visitor_in_number_keyval); + input_visitor_test_add("/visitor/input/number_str_keyval", + NULL, test_visitor_in_number_str_keyval); + input_visitor_test_add("/visitor/input/number_str_fail", + NULL, test_visitor_in_number_str_fail); + input_visitor_test_add("/visitor/input/size_str_keyval", + NULL, test_visitor_in_size_str_keyval); + input_visitor_test_add("/visitor/input/size_str_fail", + NULL, test_visitor_in_size_str_fail); input_visitor_test_add("/visitor/input/string", NULL, test_visitor_in_string); input_visitor_test_add("/visitor/input/enum", --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488872135913202.44939815185114; Mon, 6 Mar 2017 23:35:35 -0800 (PST) Received: from localhost ([::1]:48002 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9eg-0004xp-Hi for importer@patchew.org; Tue, 07 Mar 2017 02:35:34 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44565) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QO-0001aC-JI for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:50 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QK-0006A3-3P for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:48 -0500 Received: from mx1.redhat.com ([209.132.183.28]:41100) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QJ-00069Q-QG for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 03A0180463 for ; Tue, 7 Mar 2017 07:20:44 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277KfX0016274 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:42 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id CDCAF11386CE; Tue, 7 Mar 2017 08:20:37 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:18 +0100 Message-Id: <1488871237-12332-6-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Tue, 07 Mar 2017 07:20:44 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 05/24] test-keyval: Cover use with qobject input visitor X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-6-git-send-email-armbru@redhat.com> --- tests/test-keyval.c | 312 ++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 312 insertions(+) diff --git a/tests/test-keyval.c b/tests/test-keyval.c index 27f6625..1c2aeea 100644 --- a/tests/test-keyval.c +++ b/tests/test-keyval.c @@ -12,6 +12,8 @@ =20 #include "qemu/osdep.h" #include "qapi/error.h" +#include "qapi/qobject-input-visitor.h" +#include "qemu/cutils.h" #include "qemu/option.h" =20 static void test_keyval_parse(void) @@ -171,10 +173,320 @@ static void test_keyval_parse(void) g_assert(!qdict); } =20 +static void test_keyval_visit_bool(void) +{ + Error *err =3D NULL; + Visitor *v; + QDict *qdict; + bool b; + + qdict =3D keyval_parse("bool1=3Don,bool2=3Doff", NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_bool(v, "bool1", &b, &error_abort); + g_assert(b); + visit_type_bool(v, "bool2", &b, &error_abort); + g_assert(!b); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + qdict =3D keyval_parse("bool1=3Doffer", NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_bool(v, "bool1", &b, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); +} + +static void test_keyval_visit_number(void) +{ + Error *err =3D NULL; + Visitor *v; + QDict *qdict; + uint64_t u; + + /* Lower limit zero */ + qdict =3D keyval_parse("number1=3D0", NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &error_abort); + g_assert_cmpuint(u, =3D=3D, 0); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Upper limit 2^64-1 */ + qdict =3D keyval_parse("number1=3D18446744073709551615,number2=3D-1", + NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &error_abort); + g_assert_cmphex(u, =3D=3D, UINT64_MAX); + visit_type_uint64(v, "number2", &u, &error_abort); + g_assert_cmphex(u, =3D=3D, UINT64_MAX); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Above upper limit */ + qdict =3D keyval_parse("number1=3D18446744073709551616", + NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); + + /* Below lower limit */ + qdict =3D keyval_parse("number1=3D-18446744073709551616", + NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); + + /* Hex and octal */ + qdict =3D keyval_parse("number1=3D0x2a,number2=3D052", + NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &error_abort); + g_assert_cmpuint(u, =3D=3D, 42); + visit_type_uint64(v, "number2", &u, &error_abort); + g_assert_cmpuint(u, =3D=3D, 42); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Trailing crap */ + qdict =3D keyval_parse("number1=3D3.14,number2=3D08", + NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_uint64(v, "number1", &u, &err); + error_free_or_abort(&err); + visit_type_uint64(v, "number2", &u, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); +} + +static void test_keyval_visit_size(void) +{ + Error *err =3D NULL; + Visitor *v; + QDict *qdict; + uint64_t sz; + + /* Lower limit zero */ + qdict =3D keyval_parse("sz1=3D0", NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmpuint(sz, =3D=3D, 0); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Note: precision is 53 bits since we're parsing with strtod() */ + + /* Around limit of precision: 2^53-1, 2^53, 2^53+1 */ + qdict =3D keyval_parse("sz1=3D9007199254740991," + "sz2=3D9007199254740992," + "sz3=3D9007199254740993", + NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmphex(sz, =3D=3D, 0x1fffffffffffff); + visit_type_size(v, "sz2", &sz, &error_abort); + g_assert_cmphex(sz, =3D=3D, 0x20000000000000); + visit_type_size(v, "sz3", &sz, &error_abort); + g_assert_cmphex(sz, =3D=3D, 0x20000000000000); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Close to signed upper limit 0x7ffffffffffffc00 (53 msbs set) */ + qdict =3D keyval_parse("sz1=3D9223372036854774784," /* 7ffffffffffffc0= 0 */ + "sz2=3D9223372036854775295", /* 7ffffffffffffdff = */ + NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmphex(sz, =3D=3D, 0x7ffffffffffffc00); + visit_type_size(v, "sz2", &sz, &error_abort); + g_assert_cmphex(sz, =3D=3D, 0x7ffffffffffffc00); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Close to actual upper limit 0xfffffffffffff800 (53 msbs set) */ + qdict =3D keyval_parse("sz1=3D18446744073709549568," /* fffffffffffff8= 00 */ + "sz2=3D18446744073709550591", /* fffffffffffffbff= */ + NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmphex(sz, =3D=3D, 0xfffffffffffff800); + visit_type_size(v, "sz2", &sz, &error_abort); + g_assert_cmphex(sz, =3D=3D, 0xfffffffffffff800); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Beyond limits */ + qdict =3D keyval_parse("sz1=3D-1," + "sz2=3D18446744073709550592", /* fffffffffffffc00= */ + NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &err); + error_free_or_abort(&err); + visit_type_size(v, "sz2", &sz, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); + + /* Suffixes */ + qdict =3D keyval_parse("sz1=3D8b,sz2=3D1.5k,sz3=3D2M,sz4=3D0.1G,sz5=3D= 16777215T", + NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &error_abort); + g_assert_cmpuint(sz, =3D=3D, 8); + visit_type_size(v, "sz2", &sz, &error_abort); + g_assert_cmpuint(sz, =3D=3D, 1536); + visit_type_size(v, "sz3", &sz, &error_abort); + g_assert_cmphex(sz, =3D=3D, 2 * M_BYTE); + visit_type_size(v, "sz4", &sz, &error_abort); + g_assert_cmphex(sz, =3D=3D, G_BYTE / 10); + visit_type_size(v, "sz5", &sz, &error_abort); + g_assert_cmphex(sz, =3D=3D, 16777215 * T_BYTE); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + /* Beyond limit with suffix */ + qdict =3D keyval_parse("sz1=3D16777216T", NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); + + /* Trailing crap */ + qdict =3D keyval_parse("sz1=3D16E,sz2=3D16Gi", NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_type_size(v, "sz1", &sz, &err); + error_free_or_abort(&err); + visit_type_size(v, "sz2", &sz, &err); + error_free_or_abort(&err); + visit_end_struct(v, NULL); + visit_free(v); +} + +static void test_keyval_visit_dict(void) +{ + Error *err =3D NULL; + Visitor *v; + QDict *qdict; + int64_t i; + + qdict =3D keyval_parse("a.b.c=3D1,a.b.c=3D2,d=3D3", NULL, &error_abort= ); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_start_struct(v, "a", NULL, 0, &error_abort); + visit_start_struct(v, "b", NULL, 0, &error_abort); + visit_type_int(v, "c", &i, &error_abort); + g_assert_cmpint(i, =3D=3D, 2); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_type_int(v, "d", &i, &error_abort); + g_assert_cmpint(i, =3D=3D, 3); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + qdict =3D keyval_parse("a.b=3D", NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_start_struct(v, "a", NULL, 0, &error_abort); + visit_type_int(v, "c", &i, &err); /* a.c missing */ + error_free_or_abort(&err); + visit_check_struct(v, &err); + error_free_or_abort(&err); /* a.b unexpected */ + visit_end_struct(v, NULL); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); +} + +static void test_keyval_visit_optional(void) +{ + Visitor *v; + QDict *qdict; + bool present; + int64_t i; + + qdict =3D keyval_parse("a.b=3D1", NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_optional(v, "b", &present); + g_assert(!present); /* b missing */ + visit_optional(v, "a", &present); + g_assert(present); /* a present */ + visit_start_struct(v, "a", NULL, 0, &error_abort); + visit_optional(v, "b", &present); + g_assert(present); /* a.b present */ + visit_type_int(v, "b", &i, &error_abort); + g_assert_cmpint(i, =3D=3D, 1); + visit_optional(v, "a", &present); + g_assert(!present); /* a.a missing */ + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); +} + int main(int argc, char *argv[]) { g_test_init(&argc, &argv, NULL); g_test_add_func("/keyval/keyval_parse", test_keyval_parse); + g_test_add_func("/keyval/visit/bool", test_keyval_visit_bool); + g_test_add_func("/keyval/visit/number", test_keyval_visit_number); + g_test_add_func("/keyval/visit/size", test_keyval_visit_size); + g_test_add_func("/keyval/visit/dict", test_keyval_visit_dict); + g_test_add_func("/keyval/visit/optional", test_keyval_visit_optional); g_test_run(); return 0; } --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 148887182724948.55462543953877; Mon, 6 Mar 2017 23:30:27 -0800 (PST) Received: from localhost ([::1]:47975 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9Zh-0000uC-Sz for importer@patchew.org; Tue, 07 Mar 2017 02:30:25 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44380) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QK-0001XJ-8n for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:46 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QI-000698-K9 for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from mx1.redhat.com ([209.132.183.28]:59996) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QI-00068B-CJ for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:42 -0500 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9AEDF81127 for ; Tue, 7 Mar 2017 07:20:42 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277KfH7006973 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:42 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id D6E7011386DC; Tue, 7 Mar 2017 08:20:37 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:19 +0100 Message-Id: <1488871237-12332-7-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Tue, 07 Mar 2017 07:20:42 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 06/24] qapi: Factor out common part of qobject input visitor creation X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-7-git-send-email-armbru@redhat.com> --- qapi/qobject-input-visitor.c | 61 +++++++++++++++++++---------------------= ---- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c index e2e3e70..270033e 100644 --- a/qapi/qobject-input-visitor.c +++ b/qapi/qobject-input-visitor.c @@ -619,22 +619,34 @@ static void qobject_input_free(Visitor *v) g_free(qiv); } =20 +static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj) +{ + QObjectInputVisitor *v =3D g_malloc0(sizeof(*v)); + + assert(obj); + + v->visitor.type =3D VISITOR_INPUT; + v->visitor.start_struct =3D qobject_input_start_struct; + v->visitor.check_struct =3D qobject_input_check_struct; + v->visitor.end_struct =3D qobject_input_pop; + v->visitor.start_list =3D qobject_input_start_list; + v->visitor.next_list =3D qobject_input_next_list; + v->visitor.check_list =3D qobject_input_check_list; + v->visitor.end_list =3D qobject_input_pop; + v->visitor.start_alternate =3D qobject_input_start_alternate; + v->visitor.optional =3D qobject_input_optional; + v->visitor.free =3D qobject_input_free; + + v->root =3D obj; + qobject_incref(obj); + + return v; +} + Visitor *qobject_input_visitor_new(QObject *obj) { - QObjectInputVisitor *v; + QObjectInputVisitor *v =3D qobject_input_visitor_base_new(obj); =20 - assert(obj); - v =3D g_malloc0(sizeof(*v)); - - v->visitor.type =3D VISITOR_INPUT; - v->visitor.start_struct =3D qobject_input_start_struct; - v->visitor.check_struct =3D qobject_input_check_struct; - v->visitor.end_struct =3D qobject_input_pop; - v->visitor.start_list =3D qobject_input_start_list; - v->visitor.next_list =3D qobject_input_next_list; - v->visitor.check_list =3D qobject_input_check_list; - v->visitor.end_list =3D qobject_input_pop; - v->visitor.start_alternate =3D qobject_input_start_alternate; v->visitor.type_int64 =3D qobject_input_type_int64; v->visitor.type_uint64 =3D qobject_input_type_uint64; v->visitor.type_bool =3D qobject_input_type_bool; @@ -642,30 +654,14 @@ Visitor *qobject_input_visitor_new(QObject *obj) v->visitor.type_number =3D qobject_input_type_number; v->visitor.type_any =3D qobject_input_type_any; v->visitor.type_null =3D qobject_input_type_null; - v->visitor.optional =3D qobject_input_optional; - v->visitor.free =3D qobject_input_free; - - v->root =3D obj; - qobject_incref(obj); =20 return &v->visitor; } =20 Visitor *qobject_input_visitor_new_keyval(QObject *obj) { - QObjectInputVisitor *v; + QObjectInputVisitor *v =3D qobject_input_visitor_base_new(obj); =20 - v =3D g_malloc0(sizeof(*v)); - - v->visitor.type =3D VISITOR_INPUT; - v->visitor.start_struct =3D qobject_input_start_struct; - v->visitor.check_struct =3D qobject_input_check_struct; - v->visitor.end_struct =3D qobject_input_pop; - v->visitor.start_list =3D qobject_input_start_list; - v->visitor.next_list =3D qobject_input_next_list; - v->visitor.check_list =3D qobject_input_check_list; - v->visitor.end_list =3D qobject_input_pop; - v->visitor.start_alternate =3D qobject_input_start_alternate; v->visitor.type_int64 =3D qobject_input_type_int64_keyval; v->visitor.type_uint64 =3D qobject_input_type_uint64_keyval; v->visitor.type_bool =3D qobject_input_type_bool_keyval; @@ -674,11 +670,6 @@ Visitor *qobject_input_visitor_new_keyval(QObject *obj) v->visitor.type_any =3D qobject_input_type_any; v->visitor.type_null =3D qobject_input_type_null; v->visitor.type_size =3D qobject_input_type_size_keyval; - v->visitor.optional =3D qobject_input_optional; - v->visitor.free =3D qobject_input_free; - - v->root =3D obj; - qobject_incref(obj); =20 return &v->visitor; } --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871702883224.4014590071855; Mon, 6 Mar 2017 23:28:22 -0800 (PST) Received: from localhost ([::1]:47966 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9Xh-0007QL-2q for importer@patchew.org; Tue, 07 Mar 2017 02:28:21 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44381) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QK-0001XK-9L for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:46 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QI-000695-Jz for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from mx1.redhat.com ([209.132.183.28]:41326) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QI-00068C-CG for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:42 -0500 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9903FC05678C for ; Tue, 7 Mar 2017 07:20:42 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277KfcC016879 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:42 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id DF50D11385E0; Tue, 7 Mar 2017 08:20:37 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:20 +0100 Message-Id: <1488871237-12332-8-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Tue, 07 Mar 2017 07:20:42 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 07/24] qapi: Factor out common qobject_input_get_keyval() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1488317230-26248-8-git-send-email-armbru@redhat.com> --- qapi/qobject-input-visitor.c | 87 ++++++++++++++++++----------------------= ---- 1 file changed, 35 insertions(+), 52 deletions(-) diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c index 270033e..6c56040 100644 --- a/qapi/qobject-input-visitor.c +++ b/qapi/qobject-input-visitor.c @@ -151,6 +151,28 @@ static QObject *qobject_input_get_object(QObjectInputV= isitor *qiv, return obj; } =20 +static const char *qobject_input_get_keyval(QObjectInputVisitor *qiv, + const char *name, + Error **errp) +{ + QObject *qobj; + QString *qstr; + + qobj =3D qobject_input_get_object(qiv, name, true, errp); + if (!qobj) { + return NULL; + } + + qstr =3D qobject_to_qstring(qobj); + if (!qstr) { + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "string"); + return NULL; + } + + return qstring_get_str(qstr); +} + static void qdict_add_key(const char *key, QObject *obj, void *opaque) { GHashTable *h =3D opaque; @@ -343,20 +365,13 @@ static void qobject_input_type_int64_keyval(Visitor *= v, const char *name, int64_t *obj, Error **errp) { QObjectInputVisitor *qiv =3D to_qiv(v); - QObject *qobj =3D qobject_input_get_object(qiv, name, true, errp); - QString *qstr; + const char *str =3D qobject_input_get_keyval(qiv, name, errp); =20 - if (!qobj) { - return; - } - qstr =3D qobject_to_qstring(qobj); - if (!qstr) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, - full_name(qiv, name), "string"); + if (!str) { return; } =20 - if (qemu_strtoi64(qstring_get_str(qstr), NULL, 0, obj) < 0) { + if (qemu_strtoi64(str, NULL, 0, obj) < 0) { /* TODO report -ERANGE more nicely */ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, full_name(qiv, name), "integer"); @@ -388,20 +403,13 @@ static void qobject_input_type_uint64_keyval(Visitor = *v, const char *name, uint64_t *obj, Error **errp) { QObjectInputVisitor *qiv =3D to_qiv(v); - QObject *qobj =3D qobject_input_get_object(qiv, name, true, errp); - QString *qstr; + const char *str =3D qobject_input_get_keyval(qiv, name, errp); =20 - if (!qobj) { - return; - } - qstr =3D qobject_to_qstring(qobj); - if (!qstr) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, - full_name(qiv, name), "string"); + if (!str) { return; } =20 - if (qemu_strtou64(qstring_get_str(qstr), NULL, 0, obj) < 0) { + if (qemu_strtou64(str, NULL, 0, obj) < 0) { /* TODO report -ERANGE more nicely */ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, full_name(qiv, name), "integer"); @@ -432,21 +440,12 @@ static void qobject_input_type_bool_keyval(Visitor *v= , const char *name, bool *obj, Error **errp) { QObjectInputVisitor *qiv =3D to_qiv(v); - QObject *qobj =3D qobject_input_get_object(qiv, name, true, errp); - QString *qstr; - const char *str; + const char *str =3D qobject_input_get_keyval(qiv, name, errp); =20 - if (!qobj) { - return; - } - qstr =3D qobject_to_qstring(qobj); - if (!qstr) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, - full_name(qiv, name), "string"); + if (!str) { return; } =20 - str =3D qstring_get_str(qstr); if (!strcmp(str, "on")) { *obj =3D true; } else if (!strcmp(str, "off")) { @@ -509,22 +508,13 @@ static void qobject_input_type_number_keyval(Visitor = *v, const char *name, double *obj, Error **errp) { QObjectInputVisitor *qiv =3D to_qiv(v); - QObject *qobj =3D qobject_input_get_object(qiv, name, true, errp); - QString *qstr; - const char *str; + const char *str =3D qobject_input_get_keyval(qiv, name, errp); char *endp; =20 - if (!qobj) { - return; - } - qstr =3D qobject_to_qstring(qobj); - if (!qstr) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, - full_name(qiv, name), "string"); + if (!str) { return; } =20 - str =3D qstring_get_str(qstr); errno =3D 0; *obj =3D strtod(str, &endp); if (errno || endp =3D=3D str || *endp) { @@ -568,20 +558,13 @@ static void qobject_input_type_size_keyval(Visitor *v= , const char *name, uint64_t *obj, Error **errp) { QObjectInputVisitor *qiv =3D to_qiv(v); - QObject *qobj =3D qobject_input_get_object(qiv, name, true, errp); - QString *qstr; + const char *str =3D qobject_input_get_keyval(qiv, name, errp); =20 - if (!qobj) { - return; - } - qstr =3D qobject_to_qstring(qobj); - if (!qstr) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, - full_name(qiv, name), "string"); + if (!str) { return; } =20 - if (qemu_strtosz(qstring_get_str(qstr), NULL, obj) < 0) { + if (qemu_strtosz(str, NULL, obj) < 0) { /* TODO report -ERANGE more nicely */ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, full_name(qiv, name), "size"); --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 148887183214499.72901967380415; Mon, 6 Mar 2017 23:30:32 -0800 (PST) Received: from localhost ([::1]:47977 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9Zm-0000yV-TO for importer@patchew.org; Tue, 07 Mar 2017 02:30:30 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44527) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QN-0001ZC-WA for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:49 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QL-0006Bi-87 for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:47 -0500 Received: from mx1.redhat.com ([209.132.183.28]:33672) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QK-0006A7-SV for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:45 -0500 Received: from smtp.corp.redhat.com (int-mx16.intmail.prod.int.phx2.redhat.com [10.5.11.28]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 918867E9FF for ; Tue, 7 Mar 2017 07:20:42 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 31A7C2D654 for ; Tue, 7 Mar 2017 07:20:42 +0000 (UTC) Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id E33E111385E1; Tue, 7 Mar 2017 08:20:37 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:21 +0100 Message-Id: <1488871237-12332-9-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.74 on 10.5.11.28 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Tue, 07 Mar 2017 07:20:45 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 08/24] qobject: Propagate parse errors through qobject_from_jsonv() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The next few commits will put the errors to use where appropriate. Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-9-git-send-email-armbru@redhat.com> --- include/qapi/qmp/qjson.h | 3 ++- qobject/qjson.c | 12 ++++++++---- tests/libqtest.c | 2 +- tests/test-qobject-input-visitor.c | 2 +- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/include/qapi/qmp/qjson.h b/include/qapi/qmp/qjson.h index 02b1f2c..6fe42d0 100644 --- a/include/qapi/qmp/qjson.h +++ b/include/qapi/qmp/qjson.h @@ -19,7 +19,8 @@ =20 QObject *qobject_from_json(const char *string); QObject *qobject_from_jsonf(const char *string, ...) GCC_FMT_ATTR(1, 2); -QObject *qobject_from_jsonv(const char *string, va_list *ap) GCC_FMT_ATTR(= 1, 0); +QObject *qobject_from_jsonv(const char *string, va_list *ap, Error **errp) + GCC_FMT_ATTR(1, 0); =20 QString *qobject_to_json(const QObject *obj); QString *qobject_to_json_pretty(const QObject *obj); diff --git a/qobject/qjson.c b/qobject/qjson.c index 9a0de89..339c9f7 100644 --- a/qobject/qjson.c +++ b/qobject/qjson.c @@ -12,6 +12,7 @@ */ =20 #include "qemu/osdep.h" +#include "qapi/error.h" #include "qapi/qmp/json-lexer.h" #include "qapi/qmp/json-parser.h" #include "qapi/qmp/json-streamer.h" @@ -24,15 +25,17 @@ typedef struct JSONParsingState JSONMessageParser parser; va_list *ap; QObject *result; + Error *err; } JSONParsingState; =20 static void parse_json(JSONMessageParser *parser, GQueue *tokens) { JSONParsingState *s =3D container_of(parser, JSONParsingState, parser); - s->result =3D json_parser_parse(tokens, s->ap); + + s->result =3D json_parser_parse_err(tokens, s->ap, &s->err); } =20 -QObject *qobject_from_jsonv(const char *string, va_list *ap) +QObject *qobject_from_jsonv(const char *string, va_list *ap, Error **errp) { JSONParsingState state =3D {}; =20 @@ -43,12 +46,13 @@ QObject *qobject_from_jsonv(const char *string, va_list= *ap) json_message_parser_flush(&state.parser); json_message_parser_destroy(&state.parser); =20 + error_propagate(errp, state.err); return state.result; } =20 QObject *qobject_from_json(const char *string) { - return qobject_from_jsonv(string, NULL); + return qobject_from_jsonv(string, NULL, NULL); } =20 /* @@ -61,7 +65,7 @@ QObject *qobject_from_jsonf(const char *string, ...) va_list ap; =20 va_start(ap, string); - obj =3D qobject_from_jsonv(string, &ap); + obj =3D qobject_from_jsonv(string, &ap, NULL); va_end(ap); =20 assert(obj !=3D NULL); diff --git a/tests/libqtest.c b/tests/libqtest.c index ca6b641..9033c5f 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -442,7 +442,7 @@ void qmp_fd_sendv(int fd, const char *fmt, va_list ap) * is an array type. */ va_copy(ap_copy, ap); - qobj =3D qobject_from_jsonv(fmt, &ap_copy); + qobj =3D qobject_from_jsonv(fmt, &ap_copy, NULL); va_end(ap_copy); =20 /* No need to send anything for an empty QObject. */ diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-= visitor.c index 32ba492..36cc4b5 100644 --- a/tests/test-qobject-input-visitor.c +++ b/tests/test-qobject-input-visitor.c @@ -51,7 +51,7 @@ static Visitor *visitor_input_test_init_internal(TestInpu= tVisitorData *data, { visitor_input_teardown(data, NULL); =20 - data->obj =3D qobject_from_jsonv(json_string, ap); + data->obj =3D qobject_from_jsonv(json_string, ap, NULL); g_assert(data->obj); =20 if (keyval) { --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 148887131151374.06639686847836; Mon, 6 Mar 2017 23:21:51 -0800 (PST) Received: from localhost ([::1]:47935 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9RO-0001ZZ-0K for importer@patchew.org; Tue, 07 Mar 2017 02:21:50 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44382) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QK-0001XL-8e for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:46 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QI-00068m-Gz for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from mx1.redhat.com ([209.132.183.28]:34146) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QI-000688-Bm for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:42 -0500 Received: from smtp.corp.redhat.com (int-mx16.intmail.prod.int.phx2.redhat.com [10.5.11.28]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8F9D937EEB for ; Tue, 7 Mar 2017 07:20:42 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 58A772DB53 for ; Tue, 7 Mar 2017 07:20:42 +0000 (UTC) Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id E61BF11385ED; Tue, 7 Mar 2017 08:20:37 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:22 +0100 Message-Id: <1488871237-12332-10-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.74 on 10.5.11.28 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Tue, 07 Mar 2017 07:20:42 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 09/24] libqtest: Fix qmp() & friends to abort on JSON parse errors X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-10-git-send-email-armbru@redhat.com> --- tests/libqtest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/libqtest.c b/tests/libqtest.c index 9033c5f..a5c3d2b 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -21,6 +21,7 @@ #include #include =20 +#include "qapi/error.h" #include "qapi/qmp/json-parser.h" #include "qapi/qmp/json-streamer.h" #include "qapi/qmp/qjson.h" @@ -442,7 +443,7 @@ void qmp_fd_sendv(int fd, const char *fmt, va_list ap) * is an array type. */ va_copy(ap_copy, ap); - qobj =3D qobject_from_jsonv(fmt, &ap_copy, NULL); + qobj =3D qobject_from_jsonv(fmt, &ap_copy, &error_abort); va_end(ap_copy); =20 /* No need to send anything for an empty QObject. */ --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871308259911.542312161188; Mon, 6 Mar 2017 23:21:48 -0800 (PST) Received: from localhost ([::1]:47934 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9RK-0001YM-Os for importer@patchew.org; Tue, 07 Mar 2017 02:21:46 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44392) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QK-0001XR-Ar for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:45 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QI-00068x-Ic for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from mx1.redhat.com ([209.132.183.28]:58766) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QI-00068F-D7 for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:42 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9DA9B3B71B for ; Tue, 7 Mar 2017 07:20:42 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277KfmU016944 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:42 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id E92F811385F0; Tue, 7 Mar 2017 08:20:37 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:23 +0100 Message-Id: <1488871237-12332-11-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Tue, 07 Mar 2017 07:20:42 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 10/24] qjson: Abort earlier on qobject_from_jsonf() misuse X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Ignoring errors first, then asserting success is suboptimal. Pass &error_abort instead, so we abort earlier, and hopefully get more useful clues on what's wrong. Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-11-git-send-email-armbru@redhat.com> --- qobject/qjson.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qobject/qjson.c b/qobject/qjson.c index 339c9f7..c98d6a7 100644 --- a/qobject/qjson.c +++ b/qobject/qjson.c @@ -65,7 +65,7 @@ QObject *qobject_from_jsonf(const char *string, ...) va_list ap; =20 va_start(ap, string); - obj =3D qobject_from_jsonv(string, &ap, NULL); + obj =3D qobject_from_jsonv(string, &ap, &error_abort); va_end(ap); =20 assert(obj !=3D NULL); --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871308003760.3117744005488; Mon, 6 Mar 2017 23:21:48 -0800 (PST) Received: from localhost ([::1]:47933 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9RJ-0001Y4-E8 for importer@patchew.org; Tue, 07 Mar 2017 02:21:45 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44399) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QK-0001XS-Db for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:45 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QI-00069F-Oc for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from mx1.redhat.com ([209.132.183.28]:57536) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QI-00068I-Ii for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:42 -0500 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C2C4161BA5 for ; Tue, 7 Mar 2017 07:20:42 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277KfWJ007005 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:42 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id EC31A11385FC; Tue, 7 Mar 2017 08:20:37 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:24 +0100 Message-Id: <1488871237-12332-12-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 07 Mar 2017 07:20:42 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 11/24] test-qobject-input-visitor: Abort earlier on bad test input X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" visitor_input_test_init_internal() parses test input with qobject_from_jsonv(), and asserts it succeeds. Pass &error_abort for good measure. Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-12-git-send-email-armbru@redhat.com> --- tests/test-qobject-input-visitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-qobject-input-visitor.c b/tests/test-qobject-input-= visitor.c index 36cc4b5..6eb48fe 100644 --- a/tests/test-qobject-input-visitor.c +++ b/tests/test-qobject-input-visitor.c @@ -51,7 +51,7 @@ static Visitor *visitor_input_test_init_internal(TestInpu= tVisitorData *data, { visitor_input_teardown(data, NULL); =20 - data->obj =3D qobject_from_jsonv(json_string, ap, NULL); + data->obj =3D qobject_from_jsonv(json_string, ap, &error_abort); g_assert(data->obj); =20 if (keyval) { --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488872053302115.225365610675; Mon, 6 Mar 2017 23:34:13 -0800 (PST) Received: from localhost ([::1]:47997 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9dK-0003qb-TK for importer@patchew.org; Tue, 07 Mar 2017 02:34:10 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44514) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QN-0001Yv-PI for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:49 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QK-0006AR-Cs for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:47 -0500 Received: from mx1.redhat.com ([209.132.183.28]:58768) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QJ-00069V-Us for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2C9A93B71B for ; Tue, 7 Mar 2017 07:20:44 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277KfYL016302 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:43 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id EF7AD1138604; Tue, 7 Mar 2017 08:20:37 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:25 +0100 Message-Id: <1488871237-12332-13-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Tue, 07 Mar 2017 07:20:44 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 12/24] qobject: Propagate parse errors through qobject_from_json() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The next few commits will put the errors to use where appropriate. Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Reviewed-by: Eric Blake Message-Id: <1488317230-26248-13-git-send-email-armbru@redhat.com> --- block.c | 2 +- include/qapi/qmp/qjson.h | 2 +- monitor.c | 2 +- qobject/qjson.c | 4 +-- tests/check-qjson.c | 62 +++++++++++++++++++---------------= ---- tests/test-visitor-serialization.c | 2 +- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/block.c b/block.c index f293ccb..5ef5c7c 100644 --- a/block.c +++ b/block.c @@ -1262,7 +1262,7 @@ static QDict *parse_json_filename(const char *filenam= e, Error **errp) ret =3D strstart(filename, "json:", &filename); assert(ret); =20 - options_obj =3D qobject_from_json(filename); + options_obj =3D qobject_from_json(filename, NULL); if (!options_obj) { error_setg(errp, "Could not parse the JSON options"); return NULL; diff --git a/include/qapi/qmp/qjson.h b/include/qapi/qmp/qjson.h index 6fe42d0..6e84082 100644 --- a/include/qapi/qmp/qjson.h +++ b/include/qapi/qmp/qjson.h @@ -17,7 +17,7 @@ #include "qapi/qmp/qobject.h" #include "qapi/qmp/qstring.h" =20 -QObject *qobject_from_json(const char *string); +QObject *qobject_from_json(const char *string, Error **errp); QObject *qobject_from_jsonf(const char *string, ...) GCC_FMT_ATTR(1, 2); QObject *qobject_from_jsonv(const char *string, va_list *ap, Error **errp) GCC_FMT_ATTR(1, 0); diff --git a/monitor.c b/monitor.c index ec7623e..ae6c4d3 100644 --- a/monitor.c +++ b/monitor.c @@ -953,7 +953,7 @@ EventInfoList *qmp_query_events(Error **errp) static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data, Error **errp) { - *ret_data =3D qobject_from_json(qmp_schema_json); + *ret_data =3D qobject_from_json(qmp_schema_json, NULL); } =20 /* diff --git a/qobject/qjson.c b/qobject/qjson.c index c98d6a7..b2f3bfe 100644 --- a/qobject/qjson.c +++ b/qobject/qjson.c @@ -50,9 +50,9 @@ QObject *qobject_from_jsonv(const char *string, va_list *= ap, Error **errp) return state.result; } =20 -QObject *qobject_from_json(const char *string) +QObject *qobject_from_json(const char *string, Error **errp) { - return qobject_from_jsonv(string, NULL, NULL); + return qobject_from_jsonv(string, NULL, errp); } =20 /* diff --git a/tests/check-qjson.c b/tests/check-qjson.c index e6d6935..aa63758 100644 --- a/tests/check-qjson.c +++ b/tests/check-qjson.c @@ -53,7 +53,7 @@ static void escaped_string(void) QObject *obj; QString *str; =20 - obj =3D qobject_from_json(test_cases[i].encoded); + obj =3D qobject_from_json(test_cases[i].encoded, NULL); str =3D qobject_to_qstring(obj); g_assert(str); g_assert_cmpstr(qstring_get_str(str), =3D=3D, test_cases[i].decode= d); @@ -85,7 +85,7 @@ static void simple_string(void) QObject *obj; QString *str; =20 - obj =3D qobject_from_json(test_cases[i].encoded); + obj =3D qobject_from_json(test_cases[i].encoded, NULL); str =3D qobject_to_qstring(obj); g_assert(str); g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) =3D= =3D 0); @@ -116,7 +116,7 @@ static void single_quote_string(void) QObject *obj; QString *str; =20 - obj =3D qobject_from_json(test_cases[i].encoded); + obj =3D qobject_from_json(test_cases[i].encoded, NULL); str =3D qobject_to_qstring(obj); g_assert(str); g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) =3D= =3D 0); @@ -809,7 +809,7 @@ static void utf8_string(void) utf8_in =3D test_cases[i].utf8_in ?: test_cases[i].utf8_out; json_out =3D test_cases[i].json_out ?: test_cases[i].json_in; =20 - obj =3D qobject_from_json(json_in); + obj =3D qobject_from_json(json_in, NULL); if (utf8_out) { str =3D qobject_to_qstring(obj); g_assert(str); @@ -836,7 +836,7 @@ static void utf8_string(void) * FIXME Enable once these bugs have been fixed. */ if (0 && json_out !=3D json_in) { - obj =3D qobject_from_json(json_out); + obj =3D qobject_from_json(json_out, NULL); str =3D qobject_to_qstring(obj); g_assert(str); g_assert_cmpstr(qstring_get_str(str), =3D=3D, utf8_out); @@ -886,7 +886,7 @@ static void simple_number(void) for (i =3D 0; test_cases[i].encoded; i++) { QInt *qint; =20 - qint =3D qobject_to_qint(qobject_from_json(test_cases[i].encoded)); + qint =3D qobject_to_qint(qobject_from_json(test_cases[i].encoded, = NULL)); g_assert(qint); g_assert(qint_get_int(qint) =3D=3D test_cases[i].decoded); if (test_cases[i].skip =3D=3D 0) { @@ -920,7 +920,7 @@ static void float_number(void) QObject *obj; QFloat *qfloat; =20 - obj =3D qobject_from_json(test_cases[i].encoded); + obj =3D qobject_from_json(test_cases[i].encoded, NULL); qfloat =3D qobject_to_qfloat(obj); g_assert(qfloat); g_assert(qfloat_get_double(qfloat) =3D=3D test_cases[i].decoded); @@ -965,7 +965,7 @@ static void keyword_literal(void) QObject *null; QString *str; =20 - obj =3D qobject_from_json("true"); + obj =3D qobject_from_json("true", NULL); qbool =3D qobject_to_qbool(obj); g_assert(qbool); g_assert(qbool_get_bool(qbool) =3D=3D true); @@ -976,7 +976,7 @@ static void keyword_literal(void) =20 QDECREF(qbool); =20 - obj =3D qobject_from_json("false"); + obj =3D qobject_from_json("false", NULL); qbool =3D qobject_to_qbool(obj); g_assert(qbool); g_assert(qbool_get_bool(qbool) =3D=3D false); @@ -998,7 +998,7 @@ static void keyword_literal(void) g_assert(qbool_get_bool(qbool) =3D=3D true); QDECREF(qbool); =20 - obj =3D qobject_from_json("null"); + obj =3D qobject_from_json("null", NULL); g_assert(obj !=3D NULL); g_assert(qobject_type(obj) =3D=3D QTYPE_QNULL); =20 @@ -1134,13 +1134,13 @@ static void simple_dict(void) QObject *obj; QString *str; =20 - obj =3D qobject_from_json(test_cases[i].encoded); + obj =3D qobject_from_json(test_cases[i].encoded, NULL); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) =3D= =3D 1); =20 str =3D qobject_to_json(obj); qobject_decref(obj); =20 - obj =3D qobject_from_json(qstring_get_str(str)); + obj =3D qobject_from_json(qstring_get_str(str), NULL); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) =3D= =3D 1); qobject_decref(obj); QDECREF(str); @@ -1192,7 +1192,7 @@ static void large_dict(void) QObject *obj; =20 gen_test_json(gstr, 10, 100); - obj =3D qobject_from_json(gstr->str); + obj =3D qobject_from_json(gstr->str, NULL); g_assert(obj !=3D NULL); =20 qobject_decref(obj); @@ -1243,13 +1243,13 @@ static void simple_list(void) QObject *obj; QString *str; =20 - obj =3D qobject_from_json(test_cases[i].encoded); + obj =3D qobject_from_json(test_cases[i].encoded, NULL); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) =3D= =3D 1); =20 str =3D qobject_to_json(obj); qobject_decref(obj); =20 - obj =3D qobject_from_json(qstring_get_str(str)); + obj =3D qobject_from_json(qstring_get_str(str), NULL); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) =3D= =3D 1); qobject_decref(obj); QDECREF(str); @@ -1305,13 +1305,13 @@ static void simple_whitespace(void) QObject *obj; QString *str; =20 - obj =3D qobject_from_json(test_cases[i].encoded); + obj =3D qobject_from_json(test_cases[i].encoded, NULL); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) =3D= =3D 1); =20 str =3D qobject_to_json(obj); qobject_decref(obj); =20 - obj =3D qobject_from_json(qstring_get_str(str)); + obj =3D qobject_from_json(qstring_get_str(str), NULL); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) =3D= =3D 1); =20 qobject_decref(obj); @@ -1332,7 +1332,7 @@ static void simple_varargs(void) {}})), {}})); =20 - embedded_obj =3D qobject_from_json("[32, 42]"); + embedded_obj =3D qobject_from_json("[32, 42]", NULL); g_assert(embedded_obj !=3D NULL); =20 obj =3D qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj); @@ -1345,67 +1345,67 @@ static void empty_input(void) { const char *empty =3D ""; =20 - QObject *obj =3D qobject_from_json(empty); + QObject *obj =3D qobject_from_json(empty, NULL); g_assert(obj =3D=3D NULL); } =20 static void unterminated_string(void) { - QObject *obj =3D qobject_from_json("\"abc"); + QObject *obj =3D qobject_from_json("\"abc", NULL); g_assert(obj =3D=3D NULL); } =20 static void unterminated_sq_string(void) { - QObject *obj =3D qobject_from_json("'abc"); + QObject *obj =3D qobject_from_json("'abc", NULL); g_assert(obj =3D=3D NULL); } =20 static void unterminated_escape(void) { - QObject *obj =3D qobject_from_json("\"abc\\\""); + QObject *obj =3D qobject_from_json("\"abc\\\"", NULL); g_assert(obj =3D=3D NULL); } =20 static void unterminated_array(void) { - QObject *obj =3D qobject_from_json("[32"); + QObject *obj =3D qobject_from_json("[32", NULL); g_assert(obj =3D=3D NULL); } =20 static void unterminated_array_comma(void) { - QObject *obj =3D qobject_from_json("[32,"); + QObject *obj =3D qobject_from_json("[32,", NULL); g_assert(obj =3D=3D NULL); } =20 static void invalid_array_comma(void) { - QObject *obj =3D qobject_from_json("[32,}"); + QObject *obj =3D qobject_from_json("[32,}", NULL); g_assert(obj =3D=3D NULL); } =20 static void unterminated_dict(void) { - QObject *obj =3D qobject_from_json("{'abc':32"); + QObject *obj =3D qobject_from_json("{'abc':32", NULL); g_assert(obj =3D=3D NULL); } =20 static void unterminated_dict_comma(void) { - QObject *obj =3D qobject_from_json("{'abc':32,"); + QObject *obj =3D qobject_from_json("{'abc':32,", NULL); g_assert(obj =3D=3D NULL); } =20 static void invalid_dict_comma(void) { - QObject *obj =3D qobject_from_json("{'abc':32,}"); + QObject *obj =3D qobject_from_json("{'abc':32,}", NULL); g_assert(obj =3D=3D NULL); } =20 static void unterminated_literal(void) { - QObject *obj =3D qobject_from_json("nul"); + QObject *obj =3D qobject_from_json("nul", NULL); g_assert(obj =3D=3D NULL); } =20 @@ -1425,11 +1425,11 @@ static void limits_nesting(void) char buf[2 * (max_nesting + 1) + 1]; QObject *obj; =20 - obj =3D qobject_from_json(make_nest(buf, max_nesting)); + obj =3D qobject_from_json(make_nest(buf, max_nesting), NULL); g_assert(obj !=3D NULL); qobject_decref(obj); =20 - obj =3D qobject_from_json(make_nest(buf, max_nesting + 1)); + obj =3D qobject_from_json(make_nest(buf, max_nesting + 1), NULL); g_assert(obj =3D=3D NULL); } =20 diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serial= ization.c index c7e64f0..37dff41 100644 --- a/tests/test-visitor-serialization.c +++ b/tests/test-visitor-serialization.c @@ -1037,7 +1037,7 @@ static void qmp_deserialize(void **native_out, void *= datap, visit_complete(d->qov, &d->obj); obj_orig =3D d->obj; output_json =3D qobject_to_json(obj_orig); - obj =3D qobject_from_json(qstring_get_str(output_json)); + obj =3D qobject_from_json(qstring_get_str(output_json), NULL); =20 QDECREF(output_json); d->qiv =3D qobject_input_visitor_new(obj); --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871831674297.82454543130666; Mon, 6 Mar 2017 23:30:31 -0800 (PST) Received: from localhost ([::1]:47976 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9Zm-0000yR-F4 for importer@patchew.org; Tue, 07 Mar 2017 02:30:30 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44498) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QN-0001YP-Bh for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QL-0006Bs-M5 for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:47 -0500 Received: from mx1.redhat.com ([209.132.183.28]:41332) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QL-0006An-3m for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:45 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 343B4C056791 for ; Tue, 7 Mar 2017 07:20:45 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277Kfw8016303 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:43 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id F24941138607; Tue, 7 Mar 2017 08:20:37 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:26 +0100 Message-Id: <1488871237-12332-14-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Tue, 07 Mar 2017 07:20:45 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 13/24] block: More detailed syntax error reporting for JSON filenames X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-14-git-send-email-armbru@redhat.com> --- block.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index 5ef5c7c..fe7bddb 100644 --- a/block.c +++ b/block.c @@ -1262,9 +1262,14 @@ static QDict *parse_json_filename(const char *filena= me, Error **errp) ret =3D strstart(filename, "json:", &filename); assert(ret); =20 - options_obj =3D qobject_from_json(filename, NULL); + options_obj =3D qobject_from_json(filename, errp); if (!options_obj) { - error_setg(errp, "Could not parse the JSON options"); + /* Work around qobject_from_json() lossage TODO fix that */ + if (errp && !*errp) { + error_setg(errp, "Could not parse the JSON options"); + return NULL; + } + error_prepend(errp, "Could not parse the JSON options: "); return NULL; } =20 --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871575374874.0362192578114; Mon, 6 Mar 2017 23:26:15 -0800 (PST) Received: from localhost ([::1]:47959 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9Ve-0005Xe-2n for importer@patchew.org; Tue, 07 Mar 2017 02:26:14 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44455) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QM-0001Xk-3L for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:49 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QI-00069L-Ve for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:45 -0500 Received: from mx1.redhat.com ([209.132.183.28]:38764) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QI-00068M-NE for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:42 -0500 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id F14FBC03070A for ; Tue, 7 Mar 2017 07:20:42 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277Kfv0024231 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:42 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 01D6F113860A; Tue, 7 Mar 2017 08:20:38 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:27 +0100 Message-Id: <1488871237-12332-15-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Tue, 07 Mar 2017 07:20:43 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 14/24] check-qjson: Test errors from qobject_from_json() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Pass &error_abort with known-good input. Else pass &err and check what comes back. This demonstrates that the parser fails silently for many errors. Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-15-git-send-email-armbru@redhat.com> --- tests/check-qjson.c | 88 ++++++++++++++++++++++++++++++++++---------------= ---- 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/tests/check-qjson.c b/tests/check-qjson.c index aa63758..963dd46 100644 --- a/tests/check-qjson.c +++ b/tests/check-qjson.c @@ -10,8 +10,10 @@ * See the COPYING.LIB file in the top-level directory. * */ + #include "qemu/osdep.h" =20 +#include "qapi/error.h" #include "qapi/qmp/types.h" #include "qapi/qmp/qjson.h" #include "qemu-common.h" @@ -53,7 +55,7 @@ static void escaped_string(void) QObject *obj; QString *str; =20 - obj =3D qobject_from_json(test_cases[i].encoded, NULL); + obj =3D qobject_from_json(test_cases[i].encoded, &error_abort); str =3D qobject_to_qstring(obj); g_assert(str); g_assert_cmpstr(qstring_get_str(str), =3D=3D, test_cases[i].decode= d); @@ -85,7 +87,7 @@ static void simple_string(void) QObject *obj; QString *str; =20 - obj =3D qobject_from_json(test_cases[i].encoded, NULL); + obj =3D qobject_from_json(test_cases[i].encoded, &error_abort); str =3D qobject_to_qstring(obj); g_assert(str); g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) =3D= =3D 0); @@ -116,7 +118,7 @@ static void single_quote_string(void) QObject *obj; QString *str; =20 - obj =3D qobject_from_json(test_cases[i].encoded, NULL); + obj =3D qobject_from_json(test_cases[i].encoded, &error_abort); str =3D qobject_to_qstring(obj); g_assert(str); g_assert(strcmp(qstring_get_str(str), test_cases[i].decoded) =3D= =3D 0); @@ -809,7 +811,7 @@ static void utf8_string(void) utf8_in =3D test_cases[i].utf8_in ?: test_cases[i].utf8_out; json_out =3D test_cases[i].json_out ?: test_cases[i].json_in; =20 - obj =3D qobject_from_json(json_in, NULL); + obj =3D qobject_from_json(json_in, utf8_out ? &error_abort : NULL); if (utf8_out) { str =3D qobject_to_qstring(obj); g_assert(str); @@ -836,7 +838,7 @@ static void utf8_string(void) * FIXME Enable once these bugs have been fixed. */ if (0 && json_out !=3D json_in) { - obj =3D qobject_from_json(json_out, NULL); + obj =3D qobject_from_json(json_out, &error_abort); str =3D qobject_to_qstring(obj); g_assert(str); g_assert_cmpstr(qstring_get_str(str), =3D=3D, utf8_out); @@ -886,7 +888,8 @@ static void simple_number(void) for (i =3D 0; test_cases[i].encoded; i++) { QInt *qint; =20 - qint =3D qobject_to_qint(qobject_from_json(test_cases[i].encoded, = NULL)); + qint =3D qobject_to_qint(qobject_from_json(test_cases[i].encoded, + &error_abort)); g_assert(qint); g_assert(qint_get_int(qint) =3D=3D test_cases[i].decoded); if (test_cases[i].skip =3D=3D 0) { @@ -920,7 +923,7 @@ static void float_number(void) QObject *obj; QFloat *qfloat; =20 - obj =3D qobject_from_json(test_cases[i].encoded, NULL); + obj =3D qobject_from_json(test_cases[i].encoded, &error_abort); qfloat =3D qobject_to_qfloat(obj); g_assert(qfloat); g_assert(qfloat_get_double(qfloat) =3D=3D test_cases[i].decoded); @@ -965,7 +968,7 @@ static void keyword_literal(void) QObject *null; QString *str; =20 - obj =3D qobject_from_json("true", NULL); + obj =3D qobject_from_json("true", &error_abort); qbool =3D qobject_to_qbool(obj); g_assert(qbool); g_assert(qbool_get_bool(qbool) =3D=3D true); @@ -976,7 +979,7 @@ static void keyword_literal(void) =20 QDECREF(qbool); =20 - obj =3D qobject_from_json("false", NULL); + obj =3D qobject_from_json("false", &error_abort); qbool =3D qobject_to_qbool(obj); g_assert(qbool); g_assert(qbool_get_bool(qbool) =3D=3D false); @@ -998,7 +1001,7 @@ static void keyword_literal(void) g_assert(qbool_get_bool(qbool) =3D=3D true); QDECREF(qbool); =20 - obj =3D qobject_from_json("null", NULL); + obj =3D qobject_from_json("null", &error_abort); g_assert(obj !=3D NULL); g_assert(qobject_type(obj) =3D=3D QTYPE_QNULL); =20 @@ -1134,13 +1137,13 @@ static void simple_dict(void) QObject *obj; QString *str; =20 - obj =3D qobject_from_json(test_cases[i].encoded, NULL); + obj =3D qobject_from_json(test_cases[i].encoded, &error_abort); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) =3D= =3D 1); =20 str =3D qobject_to_json(obj); qobject_decref(obj); =20 - obj =3D qobject_from_json(qstring_get_str(str), NULL); + obj =3D qobject_from_json(qstring_get_str(str), &error_abort); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) =3D= =3D 1); qobject_decref(obj); QDECREF(str); @@ -1192,7 +1195,7 @@ static void large_dict(void) QObject *obj; =20 gen_test_json(gstr, 10, 100); - obj =3D qobject_from_json(gstr->str, NULL); + obj =3D qobject_from_json(gstr->str, &error_abort); g_assert(obj !=3D NULL); =20 qobject_decref(obj); @@ -1243,13 +1246,13 @@ static void simple_list(void) QObject *obj; QString *str; =20 - obj =3D qobject_from_json(test_cases[i].encoded, NULL); + obj =3D qobject_from_json(test_cases[i].encoded, &error_abort); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) =3D= =3D 1); =20 str =3D qobject_to_json(obj); qobject_decref(obj); =20 - obj =3D qobject_from_json(qstring_get_str(str), NULL); + obj =3D qobject_from_json(qstring_get_str(str), &error_abort); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) =3D= =3D 1); qobject_decref(obj); QDECREF(str); @@ -1305,13 +1308,13 @@ static void simple_whitespace(void) QObject *obj; QString *str; =20 - obj =3D qobject_from_json(test_cases[i].encoded, NULL); + obj =3D qobject_from_json(test_cases[i].encoded, &error_abort); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) =3D= =3D 1); =20 str =3D qobject_to_json(obj); qobject_decref(obj); =20 - obj =3D qobject_from_json(qstring_get_str(str), NULL); + obj =3D qobject_from_json(qstring_get_str(str), &error_abort); g_assert(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) =3D= =3D 1); =20 qobject_decref(obj); @@ -1332,7 +1335,7 @@ static void simple_varargs(void) {}})), {}})); =20 - embedded_obj =3D qobject_from_json("[32, 42]", NULL); + embedded_obj =3D qobject_from_json("[32, 42]", &error_abort); g_assert(embedded_obj !=3D NULL); =20 obj =3D qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj); @@ -1344,68 +1347,87 @@ static void simple_varargs(void) static void empty_input(void) { const char *empty =3D ""; - - QObject *obj =3D qobject_from_json(empty, NULL); + QObject *obj =3D qobject_from_json(empty, &error_abort); g_assert(obj =3D=3D NULL); } =20 static void unterminated_string(void) { - QObject *obj =3D qobject_from_json("\"abc", NULL); + Error *err =3D NULL; + QObject *obj =3D qobject_from_json("\"abc", &err); + g_assert(!err); /* BUG */ g_assert(obj =3D=3D NULL); } =20 static void unterminated_sq_string(void) { - QObject *obj =3D qobject_from_json("'abc", NULL); + Error *err =3D NULL; + QObject *obj =3D qobject_from_json("'abc", &err); + g_assert(!err); /* BUG */ g_assert(obj =3D=3D NULL); } =20 static void unterminated_escape(void) { - QObject *obj =3D qobject_from_json("\"abc\\\"", NULL); + Error *err =3D NULL; + QObject *obj =3D qobject_from_json("\"abc\\\"", &err); + g_assert(!err); /* BUG */ g_assert(obj =3D=3D NULL); } =20 static void unterminated_array(void) { - QObject *obj =3D qobject_from_json("[32", NULL); + Error *err =3D NULL; + QObject *obj =3D qobject_from_json("[32", &err); + g_assert(!err); /* BUG */ g_assert(obj =3D=3D NULL); } =20 static void unterminated_array_comma(void) { - QObject *obj =3D qobject_from_json("[32,", NULL); + Error *err =3D NULL; + QObject *obj =3D qobject_from_json("[32,", &err); + g_assert(!err); /* BUG */ g_assert(obj =3D=3D NULL); } =20 static void invalid_array_comma(void) { - QObject *obj =3D qobject_from_json("[32,}", NULL); + Error *err =3D NULL; + QObject *obj =3D qobject_from_json("[32,}", &err); + error_free_or_abort(&err); g_assert(obj =3D=3D NULL); } =20 static void unterminated_dict(void) { - QObject *obj =3D qobject_from_json("{'abc':32", NULL); + Error *err =3D NULL; + QObject *obj =3D qobject_from_json("{'abc':32", &err); + g_assert(!err); /* BUG */ g_assert(obj =3D=3D NULL); } =20 static void unterminated_dict_comma(void) { - QObject *obj =3D qobject_from_json("{'abc':32,", NULL); + Error *err =3D NULL; + QObject *obj =3D qobject_from_json("{'abc':32,", &err); + g_assert(!err); /* BUG */ g_assert(obj =3D=3D NULL); } =20 static void invalid_dict_comma(void) { - QObject *obj =3D qobject_from_json("{'abc':32,}", NULL); + Error *err =3D NULL; + QObject *obj =3D qobject_from_json("{'abc':32,}", &err); + error_free_or_abort(&err); g_assert(obj =3D=3D NULL); } =20 static void unterminated_literal(void) { - QObject *obj =3D qobject_from_json("nul", NULL); + Error *err =3D NULL; + QObject *obj =3D qobject_from_json("nul", &err); + error_free_or_abort(&err); g_assert(obj =3D=3D NULL); } =20 @@ -1421,15 +1443,17 @@ static char *make_nest(char *buf, size_t cnt) =20 static void limits_nesting(void) { + Error *err =3D NULL; enum { max_nesting =3D 1024 }; /* see qobject/json-streamer.c */ char buf[2 * (max_nesting + 1) + 1]; QObject *obj; =20 - obj =3D qobject_from_json(make_nest(buf, max_nesting), NULL); + obj =3D qobject_from_json(make_nest(buf, max_nesting), &error_abort); g_assert(obj !=3D NULL); qobject_decref(obj); =20 - obj =3D qobject_from_json(make_nest(buf, max_nesting + 1), NULL); + obj =3D qobject_from_json(make_nest(buf, max_nesting + 1), &err); + error_free_or_abort(&err); g_assert(obj =3D=3D NULL); } =20 --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871709400594.5682262721562; Mon, 6 Mar 2017 23:28:29 -0800 (PST) Received: from localhost ([::1]:47968 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9Xn-0007WK-TP for importer@patchew.org; Tue, 07 Mar 2017 02:28:27 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44538) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QO-0001ZX-5e for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:49 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QM-0006Cj-Rt for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:48 -0500 Received: from mx1.redhat.com ([209.132.183.28]:60008) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QM-0006C2-L0 for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:46 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B6FDB83F45 for ; Tue, 7 Mar 2017 07:20:46 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277Khnq016483 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:45 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 04B9A113860D; Tue, 7 Mar 2017 08:20:38 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:28 +0100 Message-Id: <1488871237-12332-16-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Tue, 07 Mar 2017 07:20:46 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 15/24] test-visitor-serialization: Pass &error_abort to qobject_from_json() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" qmp_deserialize() calls qobject_from_json() ignoring errors. It passes the result to qobject_input_visitor_new(), which asserts it's not null. Therefore, we can just as well pass &error_abort to qobject_from_json(). Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-16-git-send-email-armbru@redhat.com> --- tests/test-visitor-serialization.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serial= ization.c index 37dff41..4d47cee 100644 --- a/tests/test-visitor-serialization.c +++ b/tests/test-visitor-serialization.c @@ -1037,7 +1037,7 @@ static void qmp_deserialize(void **native_out, void *= datap, visit_complete(d->qov, &d->obj); obj_orig =3D d->obj; output_json =3D qobject_to_json(obj_orig); - obj =3D qobject_from_json(qstring_get_str(output_json), NULL); + obj =3D qobject_from_json(qstring_get_str(output_json), &error_abort); =20 QDECREF(output_json); d->qiv =3D qobject_input_visitor_new(obj); --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871709399317.11039367453463; Mon, 6 Mar 2017 23:28:29 -0800 (PST) Received: from localhost ([::1]:47969 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9Xo-0007Wk-43 for importer@patchew.org; Tue, 07 Mar 2017 02:28:28 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44467) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QM-0001Xu-Jk for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:47 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QK-0006Ay-Fe for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:46 -0500 Received: from mx1.redhat.com ([209.132.183.28]:41102) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QK-00069c-4u for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 546D980467 for ; Tue, 7 Mar 2017 07:20:44 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277KhkU024484 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:44 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 079291138610; Tue, 7 Mar 2017 08:20:38 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:29 +0100 Message-Id: <1488871237-12332-17-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Tue, 07 Mar 2017 07:20:44 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 16/24] monitor: Assert qmp_schema_json[] is sane X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" qmp_query_qmp_schema() parses qmp_schema_json[] with qobject_from_json(). This must not fail, so pass &error_abort. Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-17-git-send-email-armbru@redhat.com> --- monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index ae6c4d3..f11893e 100644 --- a/monitor.c +++ b/monitor.c @@ -953,7 +953,7 @@ EventInfoList *qmp_query_events(Error **errp) static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data, Error **errp) { - *ret_data =3D qobject_from_json(qmp_schema_json, NULL); + *ret_data =3D qobject_from_json(qmp_schema_json, &error_abort); } =20 /* --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 148887213316231.344215642048994; Mon, 6 Mar 2017 23:35:33 -0800 (PST) Received: from localhost ([::1]:48001 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9ee-0004wO-0N for importer@patchew.org; Tue, 07 Mar 2017 02:35:32 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44602) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QQ-0001cT-8L for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:53 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QP-0006F4-8C for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:50 -0500 Received: from mx1.redhat.com ([209.132.183.28]:41336) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QP-0006Dv-0y for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:49 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 88289C05678C for ; Tue, 7 Mar 2017 07:20:45 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277Kh4f017105 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:44 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 0A7881138613; Tue, 7 Mar 2017 08:20:38 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:30 +0100 Message-Id: <1488871237-12332-18-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Tue, 07 Mar 2017 07:20:46 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 17/24] test-qapi-util: New, covering qapi/qapi-util.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-18-git-send-email-armbru@redhat.com> --- tests/.gitignore | 1 + tests/Makefile.include | 3 +++ tests/test-qapi-util.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 55 insertions(+) create mode 100644 tests/test-qapi-util.c diff --git a/tests/.gitignore b/tests/.gitignore index 30b7740..a966740 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -53,6 +53,7 @@ test-mul64 test-opts-visitor test-qapi-event.[ch] test-qapi-types.[ch] +test-qapi-util test-qapi-visit.[ch] test-qdev-global-props test-qemu-opts diff --git a/tests/Makefile.include b/tests/Makefile.include index 3c34295..346345e 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -128,6 +128,8 @@ gcov-files-check-bufferiszero-y =3D util/bufferiszero.c check-unit-y +=3D tests/test-uuid$(EXESUF) check-unit-y +=3D tests/ptimer-test$(EXESUF) gcov-files-ptimer-test-y =3D hw/core/ptimer.c +check-unit-y +=3D tests/test-qapi-util$(EXESUF) +gcov-files-test-qapi-util-y =3D qapi/qapi-util.c =20 check-block-$(CONFIG_POSIX) +=3D tests/qemu-iotests-quick.sh =20 @@ -732,6 +734,7 @@ tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contr= ib/ivshmem-server/ivshmem tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o contrib/libvho= st-user/libvhost-user.o $(test-util-obj-y) tests/test-uuid$(EXESUF): tests/test-uuid.o $(test-util-obj-y) tests/test-arm-mptimer$(EXESUF): tests/test-arm-mptimer.o +tests/test-qapi-util$(EXESUF): tests/test-qapi-util.o $(test-util-obj-y) =20 tests/migration/stress$(EXESUF): tests/migration/stress.o $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"L= INK","$(TARGET_DIR)$@") diff --git a/tests/test-qapi-util.c b/tests/test-qapi-util.c new file mode 100644 index 0000000..39db8bf --- /dev/null +++ b/tests/test-qapi-util.c @@ -0,0 +1,51 @@ +/* + * Unit tests for QAPI utility functions + * + * Copyright (C) 2017 Red Hat Inc. + * + * Authors: + * Markus Armbruster , + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/util.h" +#include "test-qapi-types.h" + +static void test_qapi_enum_parse(void) +{ + Error *err =3D NULL; + int ret; + + ret =3D qapi_enum_parse(QType_lookup, NULL, QTYPE__MAX, QTYPE_NONE, + &error_abort); + g_assert_cmpint(ret, =3D=3D, QTYPE_NONE); + + ret =3D qapi_enum_parse(QType_lookup, "junk", QTYPE__MAX, -1, + NULL); + g_assert_cmpint(ret, =3D=3D, -1); + + ret =3D qapi_enum_parse(QType_lookup, "junk", QTYPE__MAX, -1, + &err); + error_free_or_abort(&err); + + ret =3D qapi_enum_parse(QType_lookup, "none", QTYPE__MAX, -1, + &error_abort); + g_assert_cmpint(ret, =3D=3D, QTYPE_NONE); + + ret =3D qapi_enum_parse(QType_lookup, QType_lookup[QTYPE__MAX - 1], + QTYPE__MAX, QTYPE__MAX - 1, + &error_abort); + g_assert_cmpint(ret, =3D=3D, QTYPE__MAX - 1); +} + +int main(int argc, char *argv[]) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/qapi/util/qapi_enum_parse", test_qapi_enum_parse); + g_test_run(); + return 0; +} --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871443393327.0552066298285; Mon, 6 Mar 2017 23:24:03 -0800 (PST) Received: from localhost ([::1]:47946 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9TW-0003bH-4R for importer@patchew.org; Tue, 07 Mar 2017 02:24:02 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44468) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QM-0001Xv-KQ for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QK-0006BI-Kw for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:46 -0500 Received: from mx1.redhat.com ([209.132.183.28]:38780) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QK-00069q-90 for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8473BC0586B4 for ; Tue, 7 Mar 2017 07:20:44 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277Khsi007198 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:44 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 0D44D1138616; Tue, 7 Mar 2017 08:20:38 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:31 +0100 Message-Id: <1488871237-12332-19-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Tue, 07 Mar 2017 07:20:44 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 18/24] qapi: New parse_qapi_name() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1488317230-26248-19-git-send-email-armbru@redhat.com> --- include/qapi/util.h | 2 ++ qapi/qapi-util.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test-qapi-util.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/include/qapi/util.h b/include/qapi/util.h index 7ad26c0..7436ed8 100644 --- a/include/qapi/util.h +++ b/include/qapi/util.h @@ -14,4 +14,6 @@ int qapi_enum_parse(const char * const lookup[], const char *buf, int max, int def, Error **errp); =20 +int parse_qapi_name(const char *name, bool complete); + #endif diff --git a/qapi/qapi-util.c b/qapi/qapi-util.c index 818730a..e28dbd0 100644 --- a/qapi/qapi-util.c +++ b/qapi/qapi-util.c @@ -33,3 +33,50 @@ int qapi_enum_parse(const char * const lookup[], const c= har *buf, error_setg(errp, "invalid parameter value: %s", buf); return def; } + +/* + * Parse a valid QAPI name from @str. + * A valid name consists of letters, digits, hyphen and underscore. + * It may be prefixed by __RFQDN_ (downstream extension), where RFQDN + * may contain only letters, digits, hyphen and period. + * The special exception for enumeration names is not implemented. + * See docs/qapi-code-gen.txt for more on QAPI naming rules. + * Keep this consistent with scripts/qapi.py! + * If @complete, the parse fails unless it consumes @str completely. + * Return its length on success, -1 on failure. + */ +int parse_qapi_name(const char *str, bool complete) +{ + const char *p =3D str; + + if (*p =3D=3D '_') { /* Downstream __RFQDN_ */ + p++; + if (*p !=3D '_') { + return -1; + } + while (*++p) { + if (!qemu_isalnum(*p) && *p !=3D '-' && *p !=3D '.') { + break; + } + } + + if (*p !=3D '_') { + return -1; + } + p++; + } + + if (!qemu_isalpha(*p)) { + return -1; + } + while (*++p) { + if (!qemu_isalnum(*p) && *p !=3D '-' && *p !=3D '_') { + break; + } + } + + if (complete && *p) { + return -1; + } + return p - str; +} diff --git a/tests/test-qapi-util.c b/tests/test-qapi-util.c index 39db8bf..e869757 100644 --- a/tests/test-qapi-util.c +++ b/tests/test-qapi-util.c @@ -42,10 +42,44 @@ static void test_qapi_enum_parse(void) g_assert_cmpint(ret, =3D=3D, QTYPE__MAX - 1); } =20 +static void test_parse_qapi_name(void) +{ + int ret; + + /* Must start with a letter */ + ret =3D parse_qapi_name("a", true); + g_assert(ret =3D=3D 1); + ret =3D parse_qapi_name("a$", false); + g_assert(ret =3D=3D 1); + ret =3D parse_qapi_name("", false); + g_assert(ret =3D=3D -1); + ret =3D parse_qapi_name("1", false); + g_assert(ret =3D=3D -1); + + /* Only letters, digits, hyphen, underscore */ + ret =3D parse_qapi_name("A-Za-z0-9_", true); + g_assert(ret =3D=3D 10); + ret =3D parse_qapi_name("A-Za-z0-9_$", false); + g_assert(ret =3D=3D 10); + ret =3D parse_qapi_name("A-Za-z0-9_$", true); + g_assert(ret =3D=3D -1); + + /* __RFQDN_ */ + ret =3D parse_qapi_name("__com.redhat_supports", true); + g_assert(ret =3D=3D 21); + ret =3D parse_qapi_name("_com.example_", false); + g_assert(ret =3D=3D -1); + ret =3D parse_qapi_name("__com.example", false); + g_assert(ret =3D=3D -1); + ret =3D parse_qapi_name("__com.example_", false); + g_assert(ret =3D=3D -1); +} + int main(int argc, char *argv[]) { g_test_init(&argc, &argv, NULL); g_test_add_func("/qapi/util/qapi_enum_parse", test_qapi_enum_parse); + g_test_add_func("/qapi/util/parse_qapi_name", test_parse_qapi_name); g_test_run(); return 0; } --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871942576472.3297513744708; Mon, 6 Mar 2017 23:32:22 -0800 (PST) Received: from localhost ([::1]:47988 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9bY-0002Tp-Mz for importer@patchew.org; Tue, 07 Mar 2017 02:32:20 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44560) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QO-0001Zy-Ha for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:49 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QM-0006Cd-Rm for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:48 -0500 Received: from mx1.redhat.com ([209.132.183.28]:58774) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QM-0006Bz-GX for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:46 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A3F7E3B71B for ; Tue, 7 Mar 2017 07:20:46 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277KhEl017108 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:45 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 102021138619; Tue, 7 Mar 2017 08:20:38 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:32 +0100 Message-Id: <1488871237-12332-20-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Tue, 07 Mar 2017 07:20:46 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 19/24] keyval: Restrict key components to valid QAPI names X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Until now, key components are separated by '.'. This leaves little room for evolving the syntax, and is incompatible with the __RFQDN_ prefix convention for downstream extensions. Since key components will be commonly used as QAPI member names by the QObject input visitor, we can just as well borrow the QAPI naming rules here: letters, digits, hyphen and period starting with a letter, with an optional __RFQDN_ prefix for downstream extensions. Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-20-git-send-email-armbru@redhat.com> --- tests/test-keyval.c | 10 ++++++++++ util/keyval.c | 12 ++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/test-keyval.c b/tests/test-keyval.c index 1c2aeea..efe27cd 100644 --- a/tests/test-keyval.c +++ b/tests/test-keyval.c @@ -41,6 +41,11 @@ static void test_keyval_parse(void) error_free_or_abort(&err); g_assert(!qdict); =20 + /* Invalid non-empty key (qemu_opts_parse() doesn't care) */ + qdict =3D keyval_parse("7up=3Dval", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + /* Overlong key */ memset(long_key, 'a', 127); long_key[127] =3D 'z'; @@ -73,6 +78,11 @@ static void test_keyval_parse(void) QDECREF(qdict); g_free(params); =20 + /* Crap after valid key */ + qdict =3D keyval_parse("key[0]=3Dval", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + /* Multiple keys, last one wins */ qdict =3D keyval_parse("a=3D1,b=3D2,,x,a=3D3", NULL, &error_abort); g_assert_cmpuint(qdict_size(qdict), =3D=3D, 2); diff --git a/util/keyval.c b/util/keyval.c index 990126f..29a6368 100644 --- a/util/keyval.c +++ b/util/keyval.c @@ -34,6 +34,8 @@ * doesn't have one, because R.a must be an object to satisfy a.b=3D1 * and a string to satisfy a=3D2. * + * Key-fragments must be valid QAPI names. + * * The length of any key-fragment must be between 1 and 127. * * Design flaw: there is no way to denote an empty non-root object. @@ -51,12 +53,12 @@ * where no-key is syntactic sugar for implied-key=3Dval-no-key. * * TODO support lists - * TODO support key-fragment with __RFQDN_ prefix (downstream extensions) */ =20 #include "qemu/osdep.h" #include "qapi/error.h" #include "qapi/qmp/qstring.h" +#include "qapi/util.h" #include "qemu/option.h" =20 /* @@ -118,6 +120,7 @@ static const char *keyval_parse_one(QDict *qdict, const= char *params, size_t len; char key_in_cur[128]; QDict *cur; + int ret; QObject *next; QString *val; =20 @@ -137,9 +140,10 @@ static const char *keyval_parse_one(QDict *qdict, cons= t char *params, cur =3D qdict; s =3D key; for (;;) { - for (len =3D 0; s + len < key_end && s[len] !=3D '.'; len++) { - } - if (!len) { + ret =3D parse_qapi_name(s, false); + len =3D ret < 0 ? 0 : ret; + assert(s + len <=3D key_end); + if (!len || (s + len < key_end && s[len] !=3D '.')) { assert(key !=3D implied_key); error_setg(errp, "Invalid parameter '%.*s'", (int)(key_end - key), key); --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488872049919817.5933830009295; Mon, 6 Mar 2017 23:34:09 -0800 (PST) Received: from localhost ([::1]:47996 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9dI-0003or-ON for importer@patchew.org; Tue, 07 Mar 2017 02:34:08 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44507) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QN-0001YY-Gq for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QK-0006B1-Ff for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:47 -0500 Received: from mx1.redhat.com ([209.132.183.28]:41330) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QK-00069h-4K for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5EA16C05678C for ; Tue, 7 Mar 2017 07:20:44 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277KhoK017156 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:44 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 132BE113861C; Tue, 7 Mar 2017 08:20:38 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:33 +0100 Message-Id: <1488871237-12332-21-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Tue, 07 Mar 2017 07:20:44 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 20/24] qapi: New qobject_input_visitor_new_str() for convenience X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Markus Armbruster Message-Id: <1488317230-26248-21-git-send-email-armbru@redhat.com> --- include/qapi/qobject-input-visitor.h | 12 ++++++++++++ qapi/qobject-input-visitor.c | 36 ++++++++++++++++++++++++++++++++= ++++ 2 files changed, 48 insertions(+) diff --git a/include/qapi/qobject-input-visitor.h b/include/qapi/qobject-in= put-visitor.h index 282f9d2..b399285 100644 --- a/include/qapi/qobject-input-visitor.h +++ b/include/qapi/qobject-input-visitor.h @@ -68,4 +68,16 @@ Visitor *qobject_input_visitor_new(QObject *obj); */ Visitor *qobject_input_visitor_new_keyval(QObject *obj); =20 +/* + * Create a QObject input visitor for parsing @str. + * + * If @str looks like JSON, parse it as JSON, else as KEY=3DVALUE,... + * @implied_key applies to KEY=3DVALUE, and works as in keyval_parse(). + * On failure, store an error through @errp and return NULL. + * On success, return a new QObject input visitor for the parse. + */ +Visitor *qobject_input_visitor_new_str(const char *str, + const char *implied_key, + Error **errp); + #endif diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c index 6c56040..1a484d5 100644 --- a/qapi/qobject-input-visitor.c +++ b/qapi/qobject-input-visitor.c @@ -18,9 +18,11 @@ #include "qapi/visitor-impl.h" #include "qemu/queue.h" #include "qemu-common.h" +#include "qapi/qmp/qjson.h" #include "qapi/qmp/types.h" #include "qapi/qmp/qerror.h" #include "qemu/cutils.h" +#include "qemu/option.h" =20 typedef struct StackObject { const char *name; /* Name of @obj in its parent, if any */ @@ -656,3 +658,37 @@ Visitor *qobject_input_visitor_new_keyval(QObject *obj) =20 return &v->visitor; } + +Visitor *qobject_input_visitor_new_str(const char *str, + const char *implied_key, + Error **errp) +{ + bool is_json =3D str[0] =3D=3D '{'; + QObject *obj; + QDict *args; + Visitor *v; + + if (is_json) { + obj =3D qobject_from_json(str, errp); + if (!obj) { + /* Work around qobject_from_json() lossage TODO fix that */ + if (errp && !*errp) { + error_setg(errp, "JSON parse error"); + return NULL; + } + return NULL; + } + args =3D qobject_to_qdict(obj); + assert(args); + v =3D qobject_input_visitor_new(QOBJECT(args)); + } else { + args =3D keyval_parse(str, implied_key, errp); + if (!args) { + return NULL; + } + v =3D qobject_input_visitor_new_keyval(QOBJECT(args)); + } + QDECREF(args); + + return v; +} --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871443619207.01357924353147; Mon, 6 Mar 2017 23:24:03 -0800 (PST) Received: from localhost ([::1]:47945 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9TW-0003a5-Dy for importer@patchew.org; Tue, 07 Mar 2017 02:24:02 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44516) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QN-0001Yw-Q2 for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:49 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QK-0006BS-LN for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:47 -0500 Received: from mx1.redhat.com ([209.132.183.28]:33670) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QK-00069s-9l for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 86F7264A4C for ; Tue, 7 Mar 2017 07:20:44 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277Khn2024489 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:44 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 1610C113861F; Tue, 7 Mar 2017 08:20:38 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:34 +0100 Message-Id: <1488871237-12332-22-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Tue, 07 Mar 2017 07:20:44 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 21/24] block: Initial implementation of -blockdev X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The new command line option -blockdev works like QMP command blockdev-add. The option argument may be given in JSON syntax, exactly as in QMP. Example usage: -blockdev '{"node-name": "foo", "driver": "raw", "file": {"driver": "fi= le", "filename": "foo.img"} }' The JSON argument doesn't exactly blend into the existing option syntax, so the traditional KEY=3DVALUE,... syntax is also supported, using dotted keys to do the nesting: -blockdev node-name=3Dfoo,driver=3Draw,file.driver=3Dfile,file.filename= =3Dfoo.img This does not yet support lists, but that will be addressed shortly. Note that calling qmp_blockdev_add() (say via qmp_marshal_block_add()) right away would crash. We need to stash the configuration for later instead. This is crudely done, and bypasses QemuOpts, even though storing configuration is what QemuOpts is for. Need to revamp option infrastructure to support QAPI types like BlockdevOptions. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Message-Id: <1488317230-26248-22-git-send-email-armbru@redhat.com> --- qemu-options.hx | 7 +++++++ vl.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/qemu-options.hx b/qemu-options.hx index 2292438..8dd8ee3 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -550,6 +550,13 @@ Use @var{file} as CD-ROM image (you cannot use @option= {-hdc} and using @file{/dev/cdrom} as filename (@pxref{host_drives}). ETEXI =20 +DEF("blockdev", HAS_ARG, QEMU_OPTION_blockdev, + "-blockdev [driver=3D]driver[,node-name=3DN][,discard=3Dignore|unmap]\= n" + " [,cache.direct=3Don|off][,cache.no-flush=3Don|off]\n" + " [,read-only=3Don|off][,detect-zeroes=3Don|off|unmap]\n" + " [,driver specific parameters...]\n" + " configure a block backend\n", QEMU_ARCH_ALL) + DEF("drive", HAS_ARG, QEMU_OPTION_drive, "-drive [file=3Dfile][,if=3Dtype][,bus=3Dn][,unit=3Dm][,media=3Dd][,in= dex=3Di]\n" " [,cyls=3Dc,heads=3Dh,secs=3Ds[,trans=3Dt]][,snapshot=3Don|off]= \n" diff --git a/vl.c b/vl.c index 71b75ef..7f1644a 100644 --- a/vl.c +++ b/vl.c @@ -95,6 +95,9 @@ int main(int argc, char **argv) #include "migration/colo.h" #include "sysemu/kvm.h" #include "sysemu/hax.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi-visit.h" #include "qapi/qmp/qjson.h" #include "qemu/option.h" #include "qemu/config-file.h" @@ -2976,6 +2979,13 @@ int main(int argc, char **argv, char **envp) Error *main_loop_err =3D NULL; Error *err =3D NULL; bool list_data_dirs =3D false; + typedef struct BlockdevOptions_queue { + BlockdevOptions *bdo; + Location loc; + QSIMPLEQ_ENTRY(BlockdevOptions_queue) entry; + } BlockdevOptions_queue; + QSIMPLEQ_HEAD(, BlockdevOptions_queue) bdo_queue + =3D QSIMPLEQ_HEAD_INITIALIZER(bdo_queue); =20 module_call_init(MODULE_INIT_TRACE); =20 @@ -3118,6 +3128,25 @@ int main(int argc, char **argv, char **envp) drive_add(IF_DEFAULT, popt->index - QEMU_OPTION_hda, optar= g, HD_OPTS); break; + case QEMU_OPTION_blockdev: + { + Visitor *v; + BlockdevOptions_queue *bdo; + + v =3D qobject_input_visitor_new_str(optarg, "driver", = &err); + if (!v) { + error_report_err(err); + exit(1); + } + + bdo =3D g_new(BlockdevOptions_queue, 1); + visit_type_BlockdevOptions(v, NULL, &bdo->bdo, + &error_fatal); + visit_free(v); + loc_save(&bdo->loc); + QSIMPLEQ_INSERT_TAIL(&bdo_queue, bdo, entry); + break; + } case QEMU_OPTION_drive: if (drive_def(optarg) =3D=3D NULL) { exit(1); @@ -4451,6 +4480,16 @@ int main(int argc, char **argv, char **envp) } =20 /* open the virtual block devices */ + while (!QSIMPLEQ_EMPTY(&bdo_queue)) { + BlockdevOptions_queue *bdo =3D QSIMPLEQ_FIRST(&bdo_queue); + + QSIMPLEQ_REMOVE_HEAD(&bdo_queue, entry); + loc_push_restore(&bdo->loc); + qmp_blockdev_add(bdo->bdo, &error_fatal); + loc_pop(&bdo->loc); + qapi_free_BlockdevOptions(bdo->bdo); + g_free(bdo); + } if (snapshot || replay_mode !=3D REPLAY_MODE_NONE) { qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, NULL, NULL); --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871448532457.69593770284825; Mon, 6 Mar 2017 23:24:08 -0800 (PST) Received: from localhost ([::1]:47947 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9Tb-0003eo-7o for importer@patchew.org; Tue, 07 Mar 2017 02:24:07 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44460) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QM-0001Xp-6Y for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:47 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QK-0006B7-GF for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:46 -0500 Received: from mx1.redhat.com ([209.132.183.28]:60002) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QK-00069e-5H for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from smtp.corp.redhat.com (int-mx16.intmail.prod.int.phx2.redhat.com [10.5.11.28]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 59FF883F44 for ; Tue, 7 Mar 2017 07:20:44 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 2320F2D655 for ; Tue, 7 Mar 2017 07:20:44 +0000 (UTC) Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 196C51138541; Tue, 7 Mar 2017 08:20:38 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:35 +0100 Message-Id: <1488871237-12332-23-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.74 on 10.5.11.28 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Tue, 07 Mar 2017 07:20:44 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 22/24] qapi: Improve how keyval input visitor reports unexpected dicts X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Incorrect option -blockdev node-name=3Dfoo,driver=3Dfile,filename=3Dfoo.img,aio.unmap=3D= on is rejected with "Invalid parameter type for 'aio', expected: string". To make sense of this, you almost have to translate it into the equivalent QMP command { "execute": "blockdev-add", "arguments": { "node-name": "foo", "driver= ": "file", "filename": "foo.img", "aio": { "unmap": true } } } Improve the error message to "Parameters 'aio.*' are unexpected". Take care not to confuse the case "unexpected nested parameters" (i.e. the object is a QDict or QList) with the case "non-string scalar parameter". The latter is a misuse of the visitor, and should perhaps be an assertion. Note that test-qobject-input-visitor exercises this misuse in test_visitor_in_int_keyval(), test_visitor_in_bool_keyval() and test_visitor_in_number_keyval(). Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-23-git-send-email-armbru@redhat.com> --- qapi/qobject-input-visitor.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c index 1a484d5..b9acd86 100644 --- a/qapi/qobject-input-visitor.c +++ b/qapi/qobject-input-visitor.c @@ -167,9 +167,18 @@ static const char *qobject_input_get_keyval(QObjectInp= utVisitor *qiv, =20 qstr =3D qobject_to_qstring(qobj); if (!qstr) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, - full_name(qiv, name), "string"); - return NULL; + switch (qobject_type(qobj)) { + case QTYPE_QDICT: + case QTYPE_QLIST: + error_setg(errp, "Parameters '%s.*' are unexpected", + full_name(qiv, name)); + return NULL; + default: + /* Non-string scalar (should this be an assertion?) */ + error_setg(errp, "Internal error: parameter %s invalid", + full_name(qiv, name)); + return NULL; + } } =20 return qstring_get_str(qstr); @@ -479,6 +488,15 @@ static void qobject_input_type_str(Visitor *v, const c= har *name, char **obj, *obj =3D g_strdup(qstring_get_str(qstr)); } =20 +static void qobject_input_type_str_keyval(Visitor *v, const char *name, + char **obj, Error **errp) +{ + QObjectInputVisitor *qiv =3D to_qiv(v); + const char *str =3D qobject_input_get_keyval(qiv, name, errp); + + *obj =3D g_strdup(str); +} + static void qobject_input_type_number(Visitor *v, const char *name, double= *obj, Error **errp) { @@ -650,7 +668,7 @@ Visitor *qobject_input_visitor_new_keyval(QObject *obj) v->visitor.type_int64 =3D qobject_input_type_int64_keyval; v->visitor.type_uint64 =3D qobject_input_type_uint64_keyval; v->visitor.type_bool =3D qobject_input_type_bool_keyval; - v->visitor.type_str =3D qobject_input_type_str; + v->visitor.type_str =3D qobject_input_type_str_keyval; v->visitor.type_number =3D qobject_input_type_number_keyval; v->visitor.type_any =3D qobject_input_type_any; v->visitor.type_null =3D qobject_input_type_null; --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488871578191651.1397673147542; Mon, 6 Mar 2017 23:26:18 -0800 (PST) Received: from localhost ([::1]:47960 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9Vh-0005bY-1b for importer@patchew.org; Tue, 07 Mar 2017 02:26:17 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44492) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QN-0001YJ-7t for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:48 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QK-0006BO-J4 for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:47 -0500 Received: from mx1.redhat.com ([209.132.183.28]:37382) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QK-00069t-Ac for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 87D2381226 for ; Tue, 7 Mar 2017 07:20:44 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277KhCe024491 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:44 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 1C65D11384AC; Tue, 7 Mar 2017 08:20:38 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:36 +0100 Message-Id: <1488871237-12332-24-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Tue, 07 Mar 2017 07:20:44 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 23/24] docs/qapi-code-gen.txt: Clarify naming rules X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Markus Armbruster Reviewed-by: Kevin Wolf Message-Id: <1488317230-26248-24-git-send-email-armbru@redhat.com> --- docs/qapi-code-gen.txt | 61 ++++++++++++++++++++++++++++++++--------------= ---- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt index 6746c10..9514d93 100644 --- a/docs/qapi-code-gen.txt +++ b/docs/qapi-code-gen.txt @@ -216,33 +216,38 @@ single-dimension array of that type; multi-dimension = arrays are not directly supported (although an array of a complex struct that contains an array member is possible). =20 +All names must begin with a letter, and contain only ASCII letters, +digits, hyphen, and underscore. There are two exceptions: enum values +may start with a digit, and names that are downstream extensions (see +section Downstream extensions) start with underscore. + +Names beginning with 'q_' are reserved for the generator, which uses +them for munging QMP names that resemble C keywords or other +problematic strings. For example, a member named "default" in qapi +becomes "q_default" in the generated C code. + Types, commands, and events share a common namespace. Therefore, generally speaking, type definitions should always use CamelCase for -user-defined type names, while built-in types are lowercase. Type -definitions should not end in 'Kind', as this namespace is used for -creating implicit C enums for visiting union types, or in 'List', as -this namespace is used for creating array types. Command names, -and member names within a type, should be all lower case with words -separated by a hyphen. However, some existing older commands and -complex types use underscore; when extending such expressions, -consistency is preferred over blindly avoiding underscore. Event -names should be ALL_CAPS with words separated by underscore. Member -names cannot start with 'has-' or 'has_', as this is reserved for -tracking optional members. +user-defined type names, while built-in types are lowercase. + +Type names ending with 'Kind' or 'List' are reserved for the +generator, which uses them for implicit union enums and array types, +respectively. + +Command names, and member names within a type, should be all lower +case with words separated by a hyphen. However, some existing older +commands and complex types use underscore; when extending such +expressions, consistency is preferred over blindly avoiding +underscore. + +Event names should be ALL_CAPS with words separated by underscore. + +Member names starting with 'has-' or 'has_' are reserved for the +generator, which uses them for tracking optional members. =20 Any name (command, event, type, member, or enum value) beginning with "x-" is marked experimental, and may be withdrawn or changed -incompatibly in a future release. All names must begin with a letter, -and contain only ASCII letters, digits, dash, and underscore. There -are two exceptions: enum values may start with a digit, and any -extensions added by downstream vendors should start with a prefix -matching "__RFQDN_" (for the reverse-fully-qualified-domain-name of -the vendor), even if the rest of the name uses dash (example: -__com.redhat_drive-mirror). Names beginning with 'q_' are reserved -for the generator: QMP names that resemble C keywords or other -problematic strings will be munged in C to use this prefix. For -example, a member named "default" in qapi becomes "q_default" in the -generated C code. +incompatibly in a future release. =20 In the rest of this document, usage lines are given for each expression type, with literal strings written in lower case and @@ -643,6 +648,18 @@ any non-empty complex type (struct, union, or alternat= e), and a pointer to that QAPI type is passed as a single argument. =20 =20 +=3D=3D=3D Downstream extensions =3D=3D=3D + +QAPI schema names that are externally visible, say in the Client JSON +Protocol, need to be managed with care. Names starting with a +downstream prefix of the form __RFQDN_ are reserved for the downstream +who controls the valid, reverse fully qualified domain name RFQDN. +RFQDN may only contain ASCII letters, digits, hyphen and period. + +Example: Red Hat, Inc. controls redhat.com, and may therefore add a +downstream command __com.redhat_drive-mirror. + + =3D=3D Client JSON Protocol introspection =3D=3D =20 Clients of a Client JSON Protocol commonly need to figure out what --=20 2.7.4 From nobody Mon Apr 29 00:01:50 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488872218431416.2915122381123; Mon, 6 Mar 2017 23:36:58 -0800 (PST) Received: from localhost ([::1]:48013 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9g1-00060E-4R for importer@patchew.org; Tue, 07 Mar 2017 02:36:57 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44577) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cl9QO-0001aM-PC for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:51 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cl9QK-0006Bc-Uh for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:48 -0500 Received: from mx1.redhat.com ([209.132.183.28]:57544) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cl9QK-00069x-K5 for qemu-devel@nongnu.org; Tue, 07 Mar 2017 02:20:44 -0500 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BA5AB61D07 for ; Tue, 7 Mar 2017 07:20:44 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-55.ams2.redhat.com [10.36.116.55]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v277KhgJ007202 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Tue, 7 Mar 2017 02:20:44 -0500 Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 1F6D711384AE; Tue, 7 Mar 2017 08:20:38 +0100 (CET) From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 7 Mar 2017 08:20:37 +0100 Message-Id: <1488871237-12332-25-git-send-email-armbru@redhat.com> In-Reply-To: <1488871237-12332-1-git-send-email-armbru@redhat.com> References: <1488871237-12332-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 07 Mar 2017 07:20:44 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v3 24/24] keyval: Support lists X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Additionally permit non-negative integers as key components. A dictionary's keys must either be all integers or none. If all keys are integers, convert the dictionary to a list. The set of keys must be [0,N]. Examples: * list.1=3Dgoner,list.0=3Dnull,list.1=3Deins,list.2=3Dzwei is equivalent to JSON [ "null", "eins", "zwei" ] * a.b.c=3D1,a.b.0=3D2 is inconsistent: a.b.c clashes with a.b.0 * list.0=3Dnull,list.2=3Deins,list.2=3Dzwei has a hole: list.1 is missing Similar design flaw as for objects: there is no way to denote an empty list. While interpreting "key absent" as empty list seems natural (removing a list member from the input string works when there are multiple ones, so why not when there's just one), it doesn't work: "key absent" already means "optional list absent", which isn't the same as "empty list present". Update the keyval object visitor to use this a.0 syntax in error messages rather than the usual a[0]. Signed-off-by: Markus Armbruster Message-Id: <1488317230-26248-25-git-send-email-armbru@redhat.com> [Off-by-one fix squashed in, as per Kevin's review] Reviewed-by: Kevin Wolf --- qapi/qobject-input-visitor.c | 6 +- tests/test-keyval.c | 122 +++++++++++++++++++++++++++++ util/keyval.c | 183 +++++++++++++++++++++++++++++++++++++++= +--- 3 files changed, 298 insertions(+), 13 deletions(-) diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c index b9acd86..865e948 100644 --- a/qapi/qobject-input-visitor.c +++ b/qapi/qobject-input-visitor.c @@ -41,6 +41,7 @@ struct QObjectInputVisitor { =20 /* Root of visit at visitor creation. */ QObject *root; + bool keyval; /* Assume @root made with keyval_parse() */ =20 /* Stack of objects being visited (all entries will be either * QDict or QList). */ @@ -73,7 +74,9 @@ static const char *full_name_nth(QObjectInputVisitor *qiv= , const char *name, g_string_prepend(qiv->errname, name ?: ""); g_string_prepend_c(qiv->errname, '.'); } else { - snprintf(buf, sizeof(buf), "[%u]", so->index); + snprintf(buf, sizeof(buf), + qiv->keyval ? ".%u" : "[%u]", + so->index); g_string_prepend(qiv->errname, buf); } name =3D so->name; @@ -673,6 +676,7 @@ Visitor *qobject_input_visitor_new_keyval(QObject *obj) v->visitor.type_any =3D qobject_input_type_any; v->visitor.type_null =3D qobject_input_type_null; v->visitor.type_size =3D qobject_input_type_size_keyval; + v->keyval =3D true; =20 return &v->visitor; } diff --git a/tests/test-keyval.c b/tests/test-keyval.c index efe27cd..71288b0 100644 --- a/tests/test-keyval.c +++ b/tests/test-keyval.c @@ -12,6 +12,7 @@ =20 #include "qemu/osdep.h" #include "qapi/error.h" +#include "qapi/qmp/qstring.h" #include "qapi/qobject-input-visitor.h" #include "qemu/cutils.h" #include "qemu/option.h" @@ -183,6 +184,72 @@ static void test_keyval_parse(void) g_assert(!qdict); } =20 +static void check_list012(QList *qlist) +{ + static const char *expected[] =3D { "null", "eins", "zwei" }; + int i; + QString *qstr; + + g_assert(qlist); + for (i =3D 0; i < ARRAY_SIZE(expected); i++) { + qstr =3D qobject_to_qstring(qlist_pop(qlist)); + g_assert(qstr); + g_assert_cmpstr(qstring_get_str(qstr), =3D=3D, expected[i]); + QDECREF(qstr); + } + g_assert(qlist_empty(qlist)); +} + +static void test_keyval_parse_list(void) +{ + Error *err =3D NULL; + QDict *qdict, *sub_qdict; + + /* Root can't be a list */ + qdict =3D keyval_parse("0=3D1", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* List elements need not be in order */ + qdict =3D keyval_parse("list.0=3Dnull,list.2=3Dzwei,list.1=3Deins", + NULL, &error_abort); + g_assert_cmpint(qdict_size(qdict), =3D=3D, 1); + check_list012(qdict_get_qlist(qdict, "list")); + QDECREF(qdict); + + /* Multiple indexes, last one wins */ + qdict =3D keyval_parse("list.1=3Dgoner,list.0=3Dnull,list.1=3Deins,lis= t.2=3Dzwei", + NULL, &error_abort); + g_assert_cmpint(qdict_size(qdict), =3D=3D, 1); + check_list012(qdict_get_qlist(qdict, "list")); + QDECREF(qdict); + + /* List at deeper nesting */ + qdict =3D keyval_parse("a.list.1=3Deins,a.list.0=3Dnull,a.list.2=3Dzwe= i", + NULL, &error_abort); + g_assert_cmpint(qdict_size(qdict), =3D=3D, 1); + sub_qdict =3D qdict_get_qdict(qdict, "a"); + g_assert_cmpint(qdict_size(sub_qdict), =3D=3D, 1); + check_list012(qdict_get_qlist(sub_qdict, "list")); + QDECREF(qdict); + + /* Inconsistent dotted keys: both list and dictionary */ + qdict =3D keyval_parse("a.b.c=3D1,a.b.0=3D2", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + qdict =3D keyval_parse("a.0.c=3D1,a.b.c=3D2", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + + /* Missing list indexes */ + qdict =3D keyval_parse("list.2=3Dlonely", NULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); + qdict =3D keyval_parse("list.0=3Dnull,list.2=3Deins,list.02=3Dzwei", N= ULL, &err); + error_free_or_abort(&err); + g_assert(!qdict); +} + static void test_keyval_visit_bool(void) { Error *err =3D NULL; @@ -459,6 +526,59 @@ static void test_keyval_visit_dict(void) visit_free(v); } =20 +static void test_keyval_visit_list(void) +{ + Error *err =3D NULL; + Visitor *v; + QDict *qdict; + char *s; + + qdict =3D keyval_parse("a.0=3D,a.1=3DI,a.2.0=3DII", NULL, &error_abort= ); + /* TODO empty list */ + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_start_list(v, "a", NULL, 0, &error_abort); + visit_type_str(v, NULL, &s, &error_abort); + g_assert_cmpstr(s, =3D=3D, ""); + g_free(s); + visit_type_str(v, NULL, &s, &error_abort); + g_assert_cmpstr(s, =3D=3D, "I"); + g_free(s); + visit_start_list(v, NULL, NULL, 0, &error_abort); + visit_type_str(v, NULL, &s, &error_abort); + g_assert_cmpstr(s, =3D=3D, "II"); + g_free(s); + visit_check_list(v, &error_abort); + visit_end_list(v, NULL); + visit_check_list(v, &error_abort); + visit_end_list(v, NULL); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); + + qdict =3D keyval_parse("a.0=3D,b.0.0=3Dhead", NULL, &error_abort); + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + QDECREF(qdict); + visit_start_struct(v, NULL, NULL, 0, &error_abort); + visit_start_list(v, "a", NULL, 0, &error_abort); + visit_check_list(v, &err); /* a[0] unexpected */ + error_free_or_abort(&err); + visit_end_list(v, NULL); + visit_start_list(v, "b", NULL, 0, &error_abort); + visit_start_list(v, NULL, NULL, 0, &error_abort); + visit_type_str(v, NULL, &s, &error_abort); + g_assert_cmpstr(s, =3D=3D, "head"); + g_free(s); + visit_type_str(v, NULL, &s, &err); /* b[0][1] missing */ + error_free_or_abort(&err); + visit_end_list(v, NULL); + visit_end_list(v, NULL); + visit_check_struct(v, &error_abort); + visit_end_struct(v, NULL); + visit_free(v); +} + static void test_keyval_visit_optional(void) { Visitor *v; @@ -492,10 +612,12 @@ int main(int argc, char *argv[]) { g_test_init(&argc, &argv, NULL); g_test_add_func("/keyval/keyval_parse", test_keyval_parse); + g_test_add_func("/keyval/keyval_parse/list", test_keyval_parse_list); g_test_add_func("/keyval/visit/bool", test_keyval_visit_bool); g_test_add_func("/keyval/visit/number", test_keyval_visit_number); g_test_add_func("/keyval/visit/size", test_keyval_visit_size); 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/optional", test_keyval_visit_optional); g_test_run(); return 0; diff --git a/util/keyval.c b/util/keyval.c index 29a6368..c316aaa 100644 --- a/util/keyval.c +++ b/util/keyval.c @@ -21,10 +21,12 @@ * * Semantics defined by reduction to JSON: * - * key-vals defines a tree of objects rooted at R + * key-vals is a tree of objects and arrays rooted at object R * where for each key-val =3D key-fragment . ... =3D val in key-vals * R op key-fragment op ... =3D val' - * where (left-associative) op is member reference L.key-fragment + * 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. * @@ -34,16 +36,16 @@ * doesn't have one, because R.a must be an object to satisfy a.b=3D1 * and a string to satisfy a=3D2. * - * Key-fragments must be valid QAPI names. + * Key-fragments must be valid QAPI names or consist only of digits. * * The length of any key-fragment must be between 1 and 127. * - * Design flaw: there is no way to denote an empty non-root object. - * While interpreting "key absent" as empty object seems natural + * Design flaw: there is no way to denote an empty array or non-root + * object. While interpreting "key absent" as empty seems natural * (removing a key-val from the input string removes the member when * there are more, so why not when it's the last), it doesn't work: - * "key absent" already means "optional object absent", which isn't - * the same as "empty object present". + * "key absent" already means "optional object/array absent", which + * isn't the same as "empty object/array present". * * Additional syntax for use with an implied key: * @@ -51,17 +53,43 @@ * val-no-key =3D / [^=3D,]* / * * where no-key is syntactic sugar for implied-key=3Dval-no-key. - * - * TODO support lists */ =20 #include "qemu/osdep.h" #include "qapi/error.h" #include "qapi/qmp/qstring.h" #include "qapi/util.h" +#include "qemu/cutils.h" #include "qemu/option.h" =20 /* + * Convert @key to a list index. + * Convert all leading digits to a (non-negative) number, capped at + * INT_MAX. + * If @end is non-null, assign a pointer to the first character after + * the number to *@end. + * Else, fail if any characters follow. + * On success, return the converted number. + * On failure, return a negative value. + * Note: since only digits are converted, no two keys can map to the + * same number, except by overflow to INT_MAX. + */ +static int key_to_index(const char *key, const char **end) +{ + int ret; + unsigned long index; + + if (*key < '0' || *key > '9') { + return -EINVAL; + } + ret =3D qemu_strtoul(key, end, 10, &index); + if (ret) { + return ret =3D=3D -ERANGE ? INT_MAX : ret; + } + return index <=3D INT_MAX ? index : INT_MAX; +} + +/* * Ensure @cur maps @key_in_cur the right way. * If @value is null, it needs to map to a QDict, else to this * QString. @@ -116,7 +144,7 @@ static const char *keyval_parse_one(QDict *qdict, const= char *params, const char *implied_key, Error **errp) { - const char *key, *key_end, *s; + const char *key, *key_end, *s, *end; size_t len; char key_in_cur[128]; QDict *cur; @@ -140,8 +168,13 @@ static const char *keyval_parse_one(QDict *qdict, cons= t char *params, cur =3D qdict; s =3D key; for (;;) { - ret =3D parse_qapi_name(s, false); - len =3D ret < 0 ? 0 : ret; + /* Want a key index (unless it's first) or a QAPI name */ + if (s !=3D key && key_to_index(s, &end) >=3D 0) { + len =3D end - s; + } else { + ret =3D parse_qapi_name(s, false); + len =3D ret < 0 ? 0 : ret; + } assert(s + len <=3D key_end); if (!len || (s + len < key_end && s[len] !=3D '.')) { assert(key !=3D implied_key); @@ -208,6 +241,125 @@ static const char *keyval_parse_one(QDict *qdict, con= st char *params, return s; } =20 +static char *reassemble_key(GSList *key) +{ + GString *s =3D g_string_new(""); + GSList *p; + + for (p =3D key; p; p =3D p->next) { + g_string_prepend_c(s, '.'); + g_string_prepend(s, (char *)p->data); + } + + return g_string_free(s, FALSE); +} + +/* + * Listify @cur recursively. + * Replace QDicts whose keys are all valid list indexes by QLists. + * @key_of_cur is the list of key fragments leading up to @cur. + * On success, return either @cur or its replacement. + * On failure, store an error through @errp and return NULL. + */ +static QObject *keyval_listify(QDict *cur, GSList *key_of_cur, Error **err= p) +{ + GSList key_node; + bool has_index, has_member; + const QDictEntry *ent; + QDict *qdict; + QObject *val; + char *key; + size_t nelt; + QObject **elt; + int index, max_index, i; + QList *list; + + key_node.next =3D key_of_cur; + + /* + * Recursively listify @cur's members, and figure out whether @cur + * itself is to be listified. + */ + has_index =3D false; + has_member =3D false; + for (ent =3D qdict_first(cur); ent; ent =3D qdict_next(cur, ent)) { + if (key_to_index(ent->key, NULL) >=3D 0) { + has_index =3D true; + } else { + has_member =3D true; + } + + qdict =3D qobject_to_qdict(ent->value); + if (!qdict) { + continue; + } + + key_node.data =3D ent->key; + val =3D keyval_listify(qdict, &key_node, errp); + if (!val) { + return NULL; + } + if (val !=3D ent->value) { + qdict_put_obj(cur, ent->key, val); + } + } + + if (has_index && has_member) { + key =3D reassemble_key(key_of_cur); + error_setg(errp, "Parameters '%s*' used inconsistently", key); + g_free(key); + return NULL; + } + if (!has_index) { + return QOBJECT(cur); + } + + /* Copy @cur's values to @elt[] */ + nelt =3D qdict_size(cur) + 1; /* one extra, for use as sentinel */ + elt =3D g_new0(QObject *, nelt); + max_index =3D -1; + for (ent =3D qdict_first(cur); ent; ent =3D qdict_next(cur, ent)) { + index =3D key_to_index(ent->key, NULL); + assert(index >=3D 0); + if (index > max_index) { + max_index =3D index; + } + /* + * We iterate @nelt times. If we get one exceeding @nelt + * here, we will put less than @nelt values into @elt[], + * triggering the error in the next loop. + */ + if ((size_t)index >=3D nelt - 1) { + continue; + } + /* Even though dict keys are distinct, indexes need not be */ + elt[index] =3D ent->value; + } + + /* + * Make a list from @elt[], reporting any missing elements. + * If we dropped an index >=3D nelt in the previous loop, this loop + * will run into the sentinel and report index @nelt missing. + */ + list =3D qlist_new(); + assert(!elt[nelt-1]); /* need the sentinel to be null */ + for (i =3D 0; i < MIN(nelt, max_index + 1); i++) { + if (!elt[i]) { + key =3D reassemble_key(key_of_cur); + error_setg(errp, "Parameter '%s%d' missing", key, i); + g_free(key); + g_free(elt); + QDECREF(list); + return NULL; + } + qobject_incref(elt[i]); + qlist_append_obj(list, elt[i]); + } + + g_free(elt); + return QOBJECT(list); +} + /* * Parse @params in QEMU's traditional KEY=3DVALUE,... syntax. * If @implied_key, the first KEY=3D can be omitted. @implied_key is @@ -219,6 +371,7 @@ QDict *keyval_parse(const char *params, const char *imp= lied_key, Error **errp) { QDict *qdict =3D qdict_new(); + QObject *listified; const char *s; =20 s =3D params; @@ -231,5 +384,11 @@ QDict *keyval_parse(const char *params, const char *im= plied_key, implied_key =3D NULL; } =20 + listified =3D keyval_listify(qdict, NULL, errp); + if (!listified) { + QDECREF(qdict); + return NULL; + } + assert(listified =3D=3D QOBJECT(qdict)); return qdict; } --=20 2.7.4