mirror of https://github.com/xqemu/xqemu.git
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_extract_subqdict(QDict *src, QDict **dst, const char *start);
|
||||||
void qdict_array_split(QDict *src, QList **dst);
|
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);
|
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;
|
const QDictEntry *entry;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
|
for (entry = qdict_first(src); entry; entry = qdict_next(src, entry)) {
|
||||||
if (strstart(entry->key, start, NULL)) {
|
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);
|
snprintf_ret = snprintf(prefix, 32, "%u.", i);
|
||||||
assert(snprintf_ret < 32);
|
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
|
// There may be either a single subordinate object (named "%u") or
|
||||||
// multiple objects (each with a key prefixed "%u."), but not both.
|
// 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
|
* qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
|
||||||
* elements from src to dest.
|
* elements from src to dest.
|
||||||
|
|
Loading…
Reference in New Issue