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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user