From: Kevin Wolf <kwolf@redhat.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, qemu-devel@nongnu.org
Subject: [Qemu-devel] [PULL 13/25] qdict: Add qdict_array_entries()
Date: Fri, 12 Jun 2015 18:23:22 +0200 [thread overview]
Message-ID: <1434126214-11681-14-git-send-email-kwolf@redhat.com> (raw)
In-Reply-To: <1434126214-11681-1-git-send-email-kwolf@redhat.com>
This counts the entries in a flattened array in a QDict without
actually splitting the QDict into a QList.
bdrv_open_image() doesn't take a QList, but rather a QDict and a key
prefix string, so this is more convenient for block drivers which have a
dynamically sized list of child nodes (e.g. Quorum) and are to be
converted to using bdrv_open_image() as the standard interface for
opening child nodes.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
include/qapi/qmp/qdict.h | 1 +
qobject/qdict.c | 78 +++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 75 insertions(+), 4 deletions(-)
diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
index d68f4eb..d20db94 100644
--- a/include/qapi/qmp/qdict.h
+++ b/include/qapi/qmp/qdict.h
@@ -70,6 +70,7 @@ void qdict_flatten(QDict *qdict);
void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
void qdict_array_split(QDict *src, QList **dst);
+int qdict_array_entries(QDict *src, const char *subqdict);
void qdict_join(QDict *dest, QDict *src, bool overwrite);
diff --git a/qobject/qdict.c b/qobject/qdict.c
index ea239f0..50c0ab3 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -597,17 +597,21 @@ void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start)
}
}
-static bool qdict_has_prefixed_entries(const QDict *src, const char *start)
+static int qdict_count_prefixed_entries(const QDict *src, const char *start)
{
const QDictEntry *entry;
+ int count = 0;
for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
if (strstart(entry->key, start, NULL)) {
- return true;
+ if (count == INT_MAX) {
+ return -ERANGE;
+ }
+ count++;
}
}
- return false;
+ return count;
}
/**
@@ -646,7 +650,8 @@ void qdict_array_split(QDict *src, QList **dst)
snprintf_ret = snprintf(prefix, 32, "%u.", i);
assert(snprintf_ret < 32);
- is_subqdict = qdict_has_prefixed_entries(src, prefix);
+ /* Overflow is the same as positive non-zero results */
+ is_subqdict = qdict_count_prefixed_entries(src, prefix);
// There may be either a single subordinate object (named "%u") or
// multiple objects (each with a key prefixed "%u."), but not both.
@@ -667,6 +672,71 @@ void qdict_array_split(QDict *src, QList **dst)
}
/**
+ * qdict_array_entries(): Returns the number of direct array entries if the
+ * sub-QDict of src specified by the prefix in subqdict (or src itself for
+ * prefix == "") is valid as an array, i.e. the length of the created list if
+ * the sub-QDict would become empty after calling qdict_array_split() on it. If
+ * the array is not valid, -EINVAL is returned.
+ */
+int qdict_array_entries(QDict *src, const char *subqdict)
+{
+ const QDictEntry *entry;
+ unsigned i;
+ unsigned entries = 0;
+ size_t subqdict_len = strlen(subqdict);
+
+ assert(!subqdict_len || subqdict[subqdict_len - 1] == '.');
+
+ /* qdict_array_split() loops until UINT_MAX, but as we want to return
+ * negative errors, we only have a signed return value here. Any additional
+ * entries will lead to -EINVAL. */
+ for (i = 0; i < INT_MAX; i++) {
+ QObject *subqobj;
+ int subqdict_entries;
+ size_t slen = 32 + subqdict_len;
+ char indexstr[slen], prefix[slen];
+ size_t snprintf_ret;
+
+ snprintf_ret = snprintf(indexstr, slen, "%s%u", subqdict, i);
+ assert(snprintf_ret < slen);
+
+ subqobj = qdict_get(src, indexstr);
+
+ snprintf_ret = snprintf(prefix, slen, "%s%u.", subqdict, i);
+ assert(snprintf_ret < slen);
+
+ subqdict_entries = qdict_count_prefixed_entries(src, prefix);
+ if (subqdict_entries < 0) {
+ return subqdict_entries;
+ }
+
+ /* There may be either a single subordinate object (named "%u") or
+ * multiple objects (each with a key prefixed "%u."), but not both. */
+ if (subqobj && subqdict_entries) {
+ return -EINVAL;
+ } else if (!subqobj && !subqdict_entries) {
+ break;
+ }
+
+ entries += subqdict_entries ? subqdict_entries : 1;
+ }
+
+ /* Consider everything handled that isn't part of the given sub-QDict */
+ for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
+ if (!strstart(qdict_entry_key(entry), subqdict, NULL)) {
+ entries++;
+ }
+ }
+
+ /* Anything left in the sub-QDict that wasn't handled? */
+ if (qdict_size(src) != entries) {
+ return -EINVAL;
+ }
+
+ return i;
+}
+
+/**
* qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
* elements from src to dest.
*
--
1.8.3.1
next prev parent reply other threads:[~2015-06-12 16:24 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-06-12 16:23 [Qemu-devel] [PULL 00/25] Block layer core and image format patches Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 01/25] iotests: remove assertIsNotNone call Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 02/25] qemu-iotests: Fix 128 if sudo required Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 03/25] qcow2: Set MIN_L2_CACHE_SIZE to 2 Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 04/25] iotests: qcow2 COW with minimal L2 cache size Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 05/25] qcow2: Add DEFAULT_L2_CACHE_CLUSTERS Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 06/25] vmdk: Fix index_in_cluster calculation in vmdk_co_get_block_status Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 07/25] vmdk: Use vmdk_find_index_in_cluster everywhere Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 08/25] raw-posix: Fix .bdrv_co_get_block_status() for unaligned image size Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 09/25] block: record new size in bdrv_dirty_bitmap_truncate Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 10/25] block: Change bitmap truncate conditional to assertion Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 11/25] block: driver should override flags in bdrv_open() Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 12/25] iotests: Add tests for overriding BDRV_O_PROTOCOL Kevin Wolf
2015-06-12 16:23 ` Kevin Wolf [this message]
2015-06-12 16:23 ` [Qemu-devel] [PULL 14/25] qdict: Add qdict_{set,copy}_default() Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 15/25] check-qdict: Test cases for new functions Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 16/25] quorum: Use bdrv_open_image() Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 17/25] vmdk: " Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 18/25] block: Use macro for cache option names Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 19/25] block: Use QemuOpts in bdrv_open_common() Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 20/25] block: Move flag inheritance to bdrv_open_inherit() Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 21/25] block: Drain requests before swapping nodes in bdrv_swap() Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 22/25] queue.h: Add QLIST_FIX_HEAD_PTR() Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 23/25] block: Add list of children to BlockDriverState Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 24/25] block: Add BlockDriverState.inherits_from Kevin Wolf
2015-06-12 16:23 ` [Qemu-devel] [PULL 25/25] block: Fix reopen flag inheritance Kevin Wolf
2015-06-15 12:24 ` [Qemu-devel] [PULL 00/25] Block layer core and image format patches Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1434126214-11681-14-git-send-email-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).