in src/pathspec.c [396:504]
static int pathspec_match_from_iterator(
git_pathspec_match_list **out,
git_iterator *iter,
uint32_t flags,
git_pathspec *ps)
{
int error = 0;
git_pathspec_match_list *m = NULL;
const git_index_entry *entry = NULL;
struct pathspec_match_context ctxt;
git_vector *patterns = &ps->pathspec;
bool find_failures = out && (flags & GIT_PATHSPEC_FIND_FAILURES) != 0;
bool failures_only = !out || (flags & GIT_PATHSPEC_FAILURES_ONLY) != 0;
size_t pos, used_ct = 0, found_files = 0;
git_index *index = NULL;
git_bitvec used_patterns;
char **file;
if (git_bitvec_init(&used_patterns, patterns->length) < 0)
return -1;
if (out) {
*out = m = pathspec_match_alloc(ps, PATHSPEC_DATATYPE_STRINGS);
GIT_ERROR_CHECK_ALLOC(m);
}
if ((error = git_iterator_reset_range(iter, ps->prefix, ps->prefix)) < 0)
goto done;
if (git_iterator_type(iter) == GIT_ITERATOR_WORKDIR &&
(error = git_repository_index__weakptr(
&index, git_iterator_owner(iter))) < 0)
goto done;
pathspec_match_context_init(
&ctxt, (flags & GIT_PATHSPEC_NO_GLOB) != 0,
git_iterator_ignore_case(iter));
while (!(error = git_iterator_advance(&entry, iter))) {
/* search for match with entry->path */
int result = git_pathspec__match_at(
&pos, patterns, &ctxt, entry->path, NULL);
/* no matches for this path */
if (result < 0)
continue;
/* if result was a negative pattern match, then don't list file */
if (!result) {
used_ct += pathspec_mark_pattern(&used_patterns, pos);
continue;
}
/* check if path is ignored and untracked */
if (index != NULL &&
git_iterator_current_is_ignored(iter) &&
git_index__find_pos(NULL, index, entry->path, 0, GIT_INDEX_STAGE_ANY) < 0)
continue;
/* mark the matched pattern as used */
used_ct += pathspec_mark_pattern(&used_patterns, pos);
++found_files;
/* if find_failures is on, check if any later patterns also match */
if (find_failures && used_ct < patterns->length)
used_ct += pathspec_mark_remaining(
&used_patterns, patterns, &ctxt, pos + 1, entry->path, NULL);
/* if only looking at failures, exit early or just continue */
if (failures_only || !out) {
if (used_ct == patterns->length)
break;
continue;
}
/* insert matched path into matches array */
if ((file = (char **)git_array_alloc(m->matches)) == NULL ||
(*file = git_pool_strdup(&m->pool, entry->path)) == NULL) {
error = -1;
goto done;
}
}
if (error < 0 && error != GIT_ITEROVER)
goto done;
error = 0;
/* insert patterns that had no matches into failures array */
if (find_failures && used_ct < patterns->length &&
(error = pathspec_build_failure_array(
&m->failures, patterns, &used_patterns, &m->pool)) < 0)
goto done;
/* if every pattern failed to match, then we have failed */
if ((flags & GIT_PATHSPEC_NO_MATCH_ERROR) != 0 && !found_files) {
git_error_set(GIT_ERROR_INVALID, "no matching files were found");
error = GIT_ENOTFOUND;
}
done:
git_bitvec_free(&used_patterns);
if (error < 0) {
pathspec_match_free(m);
if (out) *out = NULL;
}
return error;
}