qdict: Add qdict_array_entries()
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>
This commit is contained in:
parent
a68197ff5b
commit
bd50530a9f
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
@ -666,6 +671,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.
|
||||
|
Loading…
Reference in New Issue
Block a user