Commit cca5df6376fd41fb4fbbb9f8a9ff87c38079dfd5

Carlos Martín Nieto 2013-08-08T16:59:39

config: hopefully get the iterator to work on multivars

diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h
index 477d472..d5b450a 100644
--- a/include/git2/sys/config.h
+++ b/include/git2/sys/config.h
@@ -39,7 +39,7 @@ struct git_config_iterator {
 	 * Return the current entry and advance the iterator. The
 	 * memory belongs to the library.
 	 */
-	int (*next)(const git_config_entry *entry, git_config_iterator *iter);
+	int (*next)(git_config_entry *entry, git_config_iterator *iter);
 
 	/**
 	 * Free the iterator
diff --git a/src/config.c b/src/config.c
index 77c5580..f34d5dd 100644
--- a/src/config.c
+++ b/src/config.c
@@ -602,18 +602,89 @@ int git_config_get_multivar_foreach(
 	return (ret == GIT_ENOTFOUND) ? config_error_notfound(name) : 0;
 }
 
-struct config_multivar_iter {
+typedef struct {
 	git_config_iterator parent;
-};
+	git_config_iterator *current;
+	const char *name;
+	const char *regexp;
+	const git_config *cfg;
+	size_t i;
+} multivar_iter;
+
+static int find_next_backend(size_t *out, const git_config *cfg, size_t i)
+{
+	file_internal *internal;
+
+	for (; i > 0; --i) {
+		internal = git_vector_get(&cfg->files, i - 1);
+		if (!internal || !internal->file)
+			continue;
+
+		*out = i;
+		return 0;
+	}
+
+	return -1;
+}
+
+static int multivar_iter_next_empty(git_config_entry *entry, git_config_iterator *_iter)
+{
+	GIT_UNUSED(entry);
+	GIT_UNUSED(_iter);
+
+	return GIT_ITEROVER;
+}
+
+static int multivar_iter_next(git_config_entry *entry, git_config_iterator *_iter)
+{
+	multivar_iter *iter = (multivar_iter *) _iter;
+	git_config_iterator *current = iter->current;
+	file_internal *internal;
+	git_config_backend *backend;
+	size_t i;
+	int error;
+
+	if (current != NULL &&
+	    (error = current->next(entry, current)) == 0)
+		return 0;
+
+	if (error != GIT_ITEROVER)
+		return error;
+
+	do {
+		if (find_next_backend(&i, iter->cfg, iter->i) < 0)
+			return GIT_ITEROVER;
+
+		internal = git_vector_get(&iter->cfg->files, i - 1);
+		backend = internal->file;
+		if ((error = backend->get_multivar(&iter->current, backend, iter->name, iter->regexp)) < 0)
+			return -1;
+
+		iter->i = i;
+		return iter->current->next(entry, iter->current);
+
+	} while(1);
+
+	return GIT_ITEROVER;
+}
 
 int git_config_get_multivar(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp)
 {
-	struct config_multivar_iter *iter;
+	multivar_iter *iter;
+	size_t i;
 
-	iter = git__calloc(1, sizeof(struct config_multivar_iter));
+	iter = git__calloc(1, sizeof(multivar_iter));
 	GITERR_CHECK_ALLOC(iter);
 
-	/* get multivar from each */
+	if (find_next_backend(&i, cfg, cfg->files.length) < 0)
+		iter->parent.next = multivar_iter_next_empty;
+	else
+		iter->parent.next = multivar_iter_next;
+
+	iter->i = cfg->files.length;
+	iter->cfg = cfg;
+	iter->name = name;
+	iter->regexp = regexp;
 
 	*out = (git_config_iterator *) iter;
 
diff --git a/src/config_file.c b/src/config_file.c
index 5559bd4..74b2000 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -433,7 +433,7 @@ static void foreach_iter_free(git_config_iterator *_iter)
 	git__free(iter);
 }
 
-static int foreach_iter_next(git_config_entry **out, git_config_iterator *_iter)
+static int foreach_iter_next(git_config_entry *out, git_config_iterator *_iter)
 {
 	foreach_iter *iter = (foreach_iter *) _iter;
 
@@ -443,7 +443,9 @@ static int foreach_iter_next(git_config_entry **out, git_config_iterator *_iter)
 		return GIT_ITEROVER;
 
 	if (!iter->have_regex) {
-		*out = var->entry;
+		out->name = var->entry->name;
+		out->value = var->entry->value;
+
 		iter->var = var->next;
 		return 0;
 	}
@@ -453,7 +455,8 @@ static int foreach_iter_next(git_config_entry **out, git_config_iterator *_iter)
 		git_config_entry *entry = var->entry;
 		regex_t *regex = &iter->regex;;
 		if (regexec(regex, entry->value, 0, NULL, 0) == 0) {
-			*out = entry;
+			out->name = entry->name;
+			out->value = entry->value;
 			return 0;
 		}
 	} while(var != NULL);