]> git.proxmox.com Git - libgit2.git/blame - src/pathspec.c
remote: create FETCH_HEAD with a refspecless remote
[libgit2.git] / src / pathspec.c
CommitLineData
2e3d4b96 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
2e3d4b96
RB
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
d2ce27dd 8#include "git2/pathspec.h"
2b672d5b 9#include "git2/diff.h"
2e3d4b96 10#include "pathspec.h"
7bf87ab6 11#include "buf_text.h"
2e3d4b96 12#include "attr_file.h"
d2ce27dd
RB
13#include "iterator.h"
14#include "repository.h"
15#include "index.h"
2b672d5b
RB
16#include "bitvec.h"
17#include "diff.h"
2e3d4b96
RB
18
19/* what is the common non-wildcard prefix for all items in the pathspec */
20char *git_pathspec_prefix(const git_strarray *pathspec)
21{
22 git_buf prefix = GIT_BUF_INIT;
23 const char *scan;
24
25 if (!pathspec || !pathspec->count ||
7bf87ab6 26 git_buf_text_common_prefix(&prefix, pathspec) < 0)
2e3d4b96
RB
27 return NULL;
28
29 /* diff prefix will only be leading non-wildcards */
30 for (scan = prefix.ptr; *scan; ++scan) {
31 if (git__iswildcard(*scan) &&
32 (scan == prefix.ptr || (*(scan - 1) != '\\')))
33 break;
34 }
35 git_buf_truncate(&prefix, scan - prefix.ptr);
36
37 if (prefix.size <= 0) {
38 git_buf_free(&prefix);
39 return NULL;
40 }
41
7bf87ab6 42 git_buf_text_unescape(&prefix);
2e3d4b96
RB
43
44 return git_buf_detach(&prefix);
45}
46
47/* is there anything in the spec that needs to be filtered on */
0d32f39e 48bool git_pathspec_is_empty(const git_strarray *pathspec)
2e3d4b96 49{
0d32f39e 50 size_t i;
2e3d4b96 51
0d32f39e 52 if (pathspec == NULL)
2e3d4b96
RB
53 return true;
54
0d32f39e 55 for (i = 0; i < pathspec->count; ++i) {
56 const char *str = pathspec->strings[i];
57
58 if (str && str[0])
59 return false;
60 }
61
2e3d4b96
RB
62 return true;
63}
64
65/* build a vector of fnmatch patterns to evaluate efficiently */
d2ce27dd 66int git_pathspec__vinit(
2e3d4b96
RB
67 git_vector *vspec, const git_strarray *strspec, git_pool *strpool)
68{
69 size_t i;
70
71 memset(vspec, 0, sizeof(*vspec));
72
0d32f39e 73 if (git_pathspec_is_empty(strspec))
2e3d4b96
RB
74 return 0;
75
76 if (git_vector_init(vspec, strspec->count, NULL) < 0)
77 return -1;
78
79 for (i = 0; i < strspec->count; ++i) {
80 int ret;
81 const char *pattern = strspec->strings[i];
82 git_attr_fnmatch *match = git__calloc(1, sizeof(git_attr_fnmatch));
83 if (!match)
84 return -1;
85
4ba64794 86 match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE | GIT_ATTR_FNMATCH_ALLOWNEG;
2e3d4b96 87
4ba64794 88 ret = git_attr_fnmatch__parse(match, strpool, NULL, &pattern);
2e3d4b96
RB
89 if (ret == GIT_ENOTFOUND) {
90 git__free(match);
91 continue;
92 } else if (ret < 0)
93 return ret;
94
95 if (git_vector_insert(vspec, match) < 0)
96 return -1;
97 }
98
99 return 0;
100}
101
102/* free data from the pathspec vector */
d2ce27dd 103void git_pathspec__vfree(git_vector *vspec)
2e3d4b96
RB
104{
105 git_attr_fnmatch *match;
106 unsigned int i;
107
108 git_vector_foreach(vspec, i, match) {
109 git__free(match);
110 vspec->contents[i] = NULL;
111 }
112
113 git_vector_free(vspec);
114}
115
d2ce27dd
RB
116struct pathspec_match_context {
117 int fnmatch_flags;
118 int (*strcomp)(const char *, const char *);
119 int (*strncomp)(const char *, const char *, size_t);
120};
121
122static void pathspec_match_context_init(
123 struct pathspec_match_context *ctxt,
124 bool disable_fnmatch,
125 bool casefold)
126{
127 if (disable_fnmatch)
128 ctxt->fnmatch_flags = -1;
129 else if (casefold)
130 ctxt->fnmatch_flags = FNM_CASEFOLD;
131 else
132 ctxt->fnmatch_flags = 0;
133
134 if (casefold) {
135 ctxt->strcomp = git__strcasecmp;
136 ctxt->strncomp = git__strncasecmp;
137 } else {
138 ctxt->strcomp = git__strcmp;
139 ctxt->strncomp = git__strncmp;
140 }
141}
142
143static int pathspec_match_one(
144 const git_attr_fnmatch *match,
145 struct pathspec_match_context *ctxt,
146 const char *path)
147{
148 int result = (match->flags & GIT_ATTR_FNMATCH_MATCH_ALL) ? 0 : FNM_NOMATCH;
149
150 if (result == FNM_NOMATCH)
151 result = ctxt->strcomp(match->pattern, path) ? FNM_NOMATCH : 0;
152
153 if (ctxt->fnmatch_flags >= 0 && result == FNM_NOMATCH)
154 result = p_fnmatch(match->pattern, path, ctxt->fnmatch_flags);
155
156 /* if we didn't match, look for exact dirname prefix match */
157 if (result == FNM_NOMATCH &&
158 (match->flags & GIT_ATTR_FNMATCH_HASWILD) == 0 &&
159 ctxt->strncomp(path, match->pattern, match->length) == 0 &&
160 path[match->length] == '/')
161 result = 0;
162
4ba64794
RB
163 /* if we didn't match and this is a negative match, check for exact
164 * match of filename with leading '!'
165 */
166 if (result == FNM_NOMATCH &&
167 (match->flags & GIT_ATTR_FNMATCH_NEGATIVE) != 0 &&
168 *path == '!' &&
b7b77def
RB
169 ctxt->strncomp(path + 1, match->pattern, match->length) == 0 &&
170 (!path[match->length + 1] || path[match->length + 1] == '/'))
4ba64794
RB
171 return 1;
172
d2ce27dd
RB
173 if (result == 0)
174 return (match->flags & GIT_ATTR_FNMATCH_NEGATIVE) ? 0 : 1;
175 return -1;
176}
177
2b672d5b
RB
178static int git_pathspec__match_at(
179 size_t *matched_at,
180 const git_vector *vspec,
181 struct pathspec_match_context *ctxt,
182 const char *path0,
183 const char *path1)
184{
185 int result = GIT_ENOTFOUND;
186 size_t i = 0;
187 const git_attr_fnmatch *match;
188
189 git_vector_foreach(vspec, i, match) {
190 if (path0 && (result = pathspec_match_one(match, ctxt, path0)) >= 0)
191 break;
192 if (path1 && (result = pathspec_match_one(match, ctxt, path1)) >= 0)
193 break;
194 }
195
196 *matched_at = i;
197 return result;
198}
199
2e3d4b96 200/* match a path against the vectorized pathspec */
d2ce27dd
RB
201bool git_pathspec__match(
202 const git_vector *vspec,
943700ec 203 const char *path,
204 bool disable_fnmatch,
205 bool casefold,
d2ce27dd
RB
206 const char **matched_pathspec,
207 size_t *matched_at)
2e3d4b96 208{
2b672d5b
RB
209 int result;
210 size_t pos;
d2ce27dd 211 struct pathspec_match_context ctxt;
2e3d4b96 212
943700ec 213 if (matched_pathspec)
214 *matched_pathspec = NULL;
d2ce27dd
RB
215 if (matched_at)
216 *matched_at = GIT_PATHSPEC_NOMATCH;
943700ec 217
2e3d4b96
RB
218 if (!vspec || !vspec->length)
219 return true;
220
d2ce27dd 221 pathspec_match_context_init(&ctxt, disable_fnmatch, casefold);
2e3d4b96 222
2b672d5b
RB
223 result = git_pathspec__match_at(&pos, vspec, &ctxt, path, NULL);
224 if (result >= 0) {
225 if (matched_pathspec) {
226 const git_attr_fnmatch *match = git_vector_get(vspec, pos);
227 *matched_pathspec = match->pattern;
d2ce27dd 228 }
2b672d5b
RB
229
230 if (matched_at)
231 *matched_at = pos;
2e3d4b96
RB
232 }
233
2b672d5b 234 return (result > 0);
d2ce27dd 235}
1fed6b07 236
2e3d4b96 237
d2ce27dd
RB
238int git_pathspec__init(git_pathspec *ps, const git_strarray *paths)
239{
240 int error = 0;
2e3d4b96 241
d2ce27dd 242 memset(ps, 0, sizeof(*ps));
2e3d4b96 243
d2ce27dd
RB
244 ps->prefix = git_pathspec_prefix(paths);
245
246 if ((error = git_pool_init(&ps->pool, 1, 0)) < 0 ||
247 (error = git_pathspec__vinit(&ps->pathspec, paths, &ps->pool)) < 0)
248 git_pathspec__clear(ps);
249
250 return error;
251}
252
253void git_pathspec__clear(git_pathspec *ps)
254{
255 git__free(ps->prefix);
256 git_pathspec__vfree(&ps->pathspec);
257 git_pool_clear(&ps->pool);
258 memset(ps, 0, sizeof(*ps));
259}
260
261int git_pathspec_new(git_pathspec **out, const git_strarray *pathspec)
262{
263 int error = 0;
264 git_pathspec *ps = git__malloc(sizeof(git_pathspec));
265 GITERR_CHECK_ALLOC(ps);
266
267 if ((error = git_pathspec__init(ps, pathspec)) < 0) {
268 git__free(ps);
269 return error;
270 }
271
272 GIT_REFCOUNT_INC(ps);
273 *out = ps;
274 return 0;
275}
276
277static void pathspec_free(git_pathspec *ps)
278{
279 git_pathspec__clear(ps);
280 git__free(ps);
281}
282
283void git_pathspec_free(git_pathspec *ps)
284{
285 if (!ps)
286 return;
287 GIT_REFCOUNT_DEC(ps, pathspec_free);
288}
943700ec 289
d2ce27dd
RB
290int git_pathspec_matches_path(
291 const git_pathspec *ps, uint32_t flags, const char *path)
292{
293 bool no_fnmatch = (flags & GIT_PATHSPEC_NO_GLOB) != 0;
294 bool casefold = (flags & GIT_PATHSPEC_IGNORE_CASE) != 0;
295
296 assert(ps && path);
297
298 return (0 != git_pathspec__match(
299 &ps->pathspec, path, no_fnmatch, casefold, NULL, NULL));
300}
301
302static void pathspec_match_free(git_pathspec_match_list *m)
303{
304 git_pathspec_free(m->pathspec);
305 m->pathspec = NULL;
306
307 git_array_clear(m->matches);
308 git_array_clear(m->failures);
309 git_pool_clear(&m->pool);
310 git__free(m);
311}
312
2b672d5b
RB
313static git_pathspec_match_list *pathspec_match_alloc(
314 git_pathspec *ps, int datatype)
d2ce27dd
RB
315{
316 git_pathspec_match_list *m = git__calloc(1, sizeof(git_pathspec_match_list));
317
318 if (m != NULL && git_pool_init(&m->pool, 1, 0) < 0) {
319 pathspec_match_free(m);
320 m = NULL;
321 }
322
323 /* need to keep reference to pathspec and increment refcount because
324 * failures array stores pointers to the pattern strings of the
325 * pathspec that had no matches
326 */
327 GIT_REFCOUNT_INC(ps);
328 m->pathspec = ps;
2b672d5b 329 m->datatype = datatype;
d2ce27dd
RB
330
331 return m;
332}
333
2b672d5b
RB
334GIT_INLINE(size_t) pathspec_mark_pattern(git_bitvec *used, size_t pos)
335{
336 if (!git_bitvec_get(used, pos)) {
337 git_bitvec_set(used, pos, true);
338 return 1;
339 }
340
341 return 0;
342}
343
344static size_t pathspec_mark_remaining(
345 git_bitvec *used,
346 git_vector *patterns,
347 struct pathspec_match_context *ctxt,
348 size_t start,
349 const char *path0,
350 const char *path1)
351{
352 size_t count = 0;
353
354 if (path1 == path0)
355 path1 = NULL;
356
357 for (; start < patterns->length; ++start) {
358 const git_attr_fnmatch *pat = git_vector_get(patterns, start);
359
360 if (git_bitvec_get(used, start))
361 continue;
362
363 if (path0 && pathspec_match_one(pat, ctxt, path0) > 0)
364 count += pathspec_mark_pattern(used, start);
365 else if (path1 && pathspec_match_one(pat, ctxt, path1) > 0)
366 count += pathspec_mark_pattern(used, start);
367 }
368
369 return count;
370}
371
372static int pathspec_build_failure_array(
373 git_pathspec_string_array_t *failures,
374 git_vector *patterns,
375 git_bitvec *used,
376 git_pool *pool)
d2ce27dd 377{
2b672d5b
RB
378 size_t pos;
379 char **failed;
380 const git_attr_fnmatch *pat;
381
382 for (pos = 0; pos < patterns->length; ++pos) {
383 if (git_bitvec_get(used, pos))
384 continue;
385
386 if ((failed = git_array_alloc(*failures)) == NULL)
387 return -1;
388
389 pat = git_vector_get(patterns, pos);
390
391 if ((*failed = git_pool_strdup(pool, pat->pattern)) == NULL)
392 return -1;
d2ce27dd 393 }
2b672d5b
RB
394
395 return 0;
d2ce27dd
RB
396}
397
398static int pathspec_match_from_iterator(
399 git_pathspec_match_list **out,
400 git_iterator *iter,
401 uint32_t flags,
402 git_pathspec *ps)
403{
404 int error = 0;
a8b5f116 405 git_pathspec_match_list *m = NULL;
d2ce27dd
RB
406 const git_index_entry *entry = NULL;
407 struct pathspec_match_context ctxt;
408 git_vector *patterns = &ps->pathspec;
2b672d5b
RB
409 bool find_failures = out && (flags & GIT_PATHSPEC_FIND_FAILURES) != 0;
410 bool failures_only = !out || (flags & GIT_PATHSPEC_FAILURES_ONLY) != 0;
d2ce27dd
RB
411 size_t pos, used_ct = 0, found_files = 0;
412 git_index *index = NULL;
2b672d5b 413 git_bitvec used_patterns;
d2ce27dd
RB
414 char **file;
415
2b672d5b
RB
416 if (git_bitvec_init(&used_patterns, patterns->length) < 0)
417 return -1;
418
a8b5f116 419 if (out) {
2b672d5b 420 *out = m = pathspec_match_alloc(ps, PATHSPEC_DATATYPE_STRINGS);
a8b5f116 421 GITERR_CHECK_ALLOC(m);
a8b5f116 422 }
d2ce27dd
RB
423
424 if ((error = git_iterator_reset(iter, ps->prefix, ps->prefix)) < 0)
425 goto done;
426
d2ce27dd
RB
427 if (git_iterator_type(iter) == GIT_ITERATOR_TYPE_WORKDIR &&
428 (error = git_repository_index__weakptr(
429 &index, git_iterator_owner(iter))) < 0)
430 goto done;
431
2b672d5b
RB
432 pathspec_match_context_init(
433 &ctxt, (flags & GIT_PATHSPEC_NO_GLOB) != 0,
434 git_iterator_ignore_case(iter));
d2ce27dd
RB
435
436 while (!(error = git_iterator_advance(&entry, iter))) {
2b672d5b
RB
437 /* search for match with entry->path */
438 int result = git_pathspec__match_at(
439 &pos, patterns, &ctxt, entry->path, NULL);
d2ce27dd
RB
440
441 /* no matches for this path */
442 if (result < 0)
443 continue;
444
445 /* if result was a negative pattern match, then don't list file */
446 if (!result) {
2b672d5b 447 used_ct += pathspec_mark_pattern(&used_patterns, pos);
d2ce27dd
RB
448 continue;
449 }
450
2b672d5b 451 /* check if path is ignored and untracked */
d2ce27dd
RB
452 if (index != NULL &&
453 git_iterator_current_is_ignored(iter) &&
454 git_index__find(NULL, index, entry->path, GIT_INDEX_STAGE_ANY) < 0)
455 continue;
456
457 /* mark the matched pattern as used */
2b672d5b 458 used_ct += pathspec_mark_pattern(&used_patterns, pos);
d2ce27dd
RB
459 ++found_files;
460
461 /* if find_failures is on, check if any later patterns also match */
2b672d5b
RB
462 if (find_failures && used_ct < patterns->length)
463 used_ct += pathspec_mark_remaining(
464 &used_patterns, patterns, &ctxt, pos + 1, entry->path, NULL);
d2ce27dd
RB
465
466 /* if only looking at failures, exit early or just continue */
a8b5f116 467 if (failures_only || !out) {
d2ce27dd
RB
468 if (used_ct == patterns->length)
469 break;
470 continue;
471 }
472
473 /* insert matched path into matches array */
2b672d5b 474 if ((file = (char **)git_array_alloc(m->matches)) == NULL ||
d2ce27dd
RB
475 (*file = git_pool_strdup(&m->pool, entry->path)) == NULL) {
476 error = -1;
477 goto done;
943700ec 478 }
2e3d4b96
RB
479 }
480
d2ce27dd
RB
481 if (error < 0 && error != GIT_ITEROVER)
482 goto done;
483 error = 0;
484
485 /* insert patterns that had no matches into failures array */
2b672d5b
RB
486 if (find_failures && used_ct < patterns->length &&
487 (error = pathspec_build_failure_array(
488 &m->failures, patterns, &used_patterns, &m->pool)) < 0)
489 goto done;
d2ce27dd
RB
490
491 /* if every pattern failed to match, then we have failed */
492 if ((flags & GIT_PATHSPEC_NO_MATCH_ERROR) != 0 && !found_files) {
493 giterr_set(GITERR_INVALID, "No matching files were found");
494 error = GIT_ENOTFOUND;
495 }
496
497done:
2b672d5b 498 git_bitvec_free(&used_patterns);
d2ce27dd
RB
499
500 if (error < 0) {
501 pathspec_match_free(m);
a8b5f116 502 if (out) *out = NULL;
d2ce27dd
RB
503 }
504
505 return error;
2e3d4b96
RB
506}
507
d2ce27dd
RB
508static git_iterator_flag_t pathspec_match_iter_flags(uint32_t flags)
509{
510 git_iterator_flag_t f = 0;
511
512 if ((flags & GIT_PATHSPEC_IGNORE_CASE) != 0)
513 f |= GIT_ITERATOR_IGNORE_CASE;
514 else if ((flags & GIT_PATHSPEC_USE_CASE) != 0)
515 f |= GIT_ITERATOR_DONT_IGNORE_CASE;
e91f9a8f 516
d2ce27dd
RB
517 return f;
518}
519
520int git_pathspec_match_workdir(
521 git_pathspec_match_list **out,
522 git_repository *repo,
523 uint32_t flags,
524 git_pathspec *ps)
e91f9a8f
RB
525{
526 int error = 0;
d2ce27dd
RB
527 git_iterator *iter;
528
a8b5f116 529 assert(repo);
e91f9a8f 530
d2ce27dd
RB
531 if (!(error = git_iterator_for_workdir(
532 &iter, repo, pathspec_match_iter_flags(flags), NULL, NULL))) {
e91f9a8f 533
d2ce27dd 534 error = pathspec_match_from_iterator(out, iter, flags, ps);
e91f9a8f 535
d2ce27dd
RB
536 git_iterator_free(iter);
537 }
e91f9a8f
RB
538
539 return error;
540}
541
d2ce27dd
RB
542int git_pathspec_match_index(
543 git_pathspec_match_list **out,
544 git_index *index,
545 uint32_t flags,
546 git_pathspec *ps)
547{
548 int error = 0;
549 git_iterator *iter;
550
a8b5f116 551 assert(index);
d2ce27dd
RB
552
553 if (!(error = git_iterator_for_index(
554 &iter, index, pathspec_match_iter_flags(flags), NULL, NULL))) {
555
556 error = pathspec_match_from_iterator(out, iter, flags, ps);
557
558 git_iterator_free(iter);
559 }
560
561 return error;
562}
563
564int git_pathspec_match_tree(
565 git_pathspec_match_list **out,
566 git_tree *tree,
567 uint32_t flags,
568 git_pathspec *ps)
569{
570 int error = 0;
571 git_iterator *iter;
572
a8b5f116 573 assert(tree);
d2ce27dd
RB
574
575 if (!(error = git_iterator_for_tree(
576 &iter, tree, pathspec_match_iter_flags(flags), NULL, NULL))) {
577
578 error = pathspec_match_from_iterator(out, iter, flags, ps);
579
580 git_iterator_free(iter);
581 }
582
583 return error;
584}
585
2b672d5b
RB
586int git_pathspec_match_diff(
587 git_pathspec_match_list **out,
3ff1d123 588 git_diff *diff,
2b672d5b
RB
589 uint32_t flags,
590 git_pathspec *ps)
591{
592 int error = 0;
593 git_pathspec_match_list *m = NULL;
594 struct pathspec_match_context ctxt;
595 git_vector *patterns = &ps->pathspec;
596 bool find_failures = out && (flags & GIT_PATHSPEC_FIND_FAILURES) != 0;
597 bool failures_only = !out || (flags & GIT_PATHSPEC_FAILURES_ONLY) != 0;
598 size_t i, pos, used_ct = 0, found_deltas = 0;
599 const git_diff_delta *delta, **match;
600 git_bitvec used_patterns;
601
602 assert(diff);
603
604 if (git_bitvec_init(&used_patterns, patterns->length) < 0)
605 return -1;
606
607 if (out) {
608 *out = m = pathspec_match_alloc(ps, PATHSPEC_DATATYPE_DIFF);
609 GITERR_CHECK_ALLOC(m);
610 }
611
612 pathspec_match_context_init(
613 &ctxt, (flags & GIT_PATHSPEC_NO_GLOB) != 0,
614 git_diff_is_sorted_icase(diff));
615
616 git_vector_foreach(&diff->deltas, i, delta) {
617 /* search for match with delta */
618 int result = git_pathspec__match_at(
619 &pos, patterns, &ctxt, delta->old_file.path, delta->new_file.path);
620
621 /* no matches for this path */
622 if (result < 0)
623 continue;
624
625 /* mark the matched pattern as used */
626 used_ct += pathspec_mark_pattern(&used_patterns, pos);
627
628 /* if result was a negative pattern match, then don't list file */
629 if (!result)
630 continue;
631
632 ++found_deltas;
633
634 /* if find_failures is on, check if any later patterns also match */
635 if (find_failures && used_ct < patterns->length)
636 used_ct += pathspec_mark_remaining(
637 &used_patterns, patterns, &ctxt, pos + 1,
638 delta->old_file.path, delta->new_file.path);
639
640 /* if only looking at failures, exit early or just continue */
641 if (failures_only || !out) {
642 if (used_ct == patterns->length)
643 break;
644 continue;
645 }
646
647 /* insert matched delta into matches array */
648 if (!(match = (const git_diff_delta **)git_array_alloc(m->matches))) {
649 error = -1;
650 goto done;
651 } else {
652 *match = delta;
653 }
654 }
655
656 /* insert patterns that had no matches into failures array */
657 if (find_failures && used_ct < patterns->length &&
658 (error = pathspec_build_failure_array(
659 &m->failures, patterns, &used_patterns, &m->pool)) < 0)
660 goto done;
661
662 /* if every pattern failed to match, then we have failed */
663 if ((flags & GIT_PATHSPEC_NO_MATCH_ERROR) != 0 && !found_deltas) {
664 giterr_set(GITERR_INVALID, "No matching deltas were found");
665 error = GIT_ENOTFOUND;
666 }
667
668done:
669 git_bitvec_free(&used_patterns);
670
671 if (error < 0) {
672 pathspec_match_free(m);
673 if (out) *out = NULL;
674 }
675
676 return error;
677}
678
d2ce27dd
RB
679void git_pathspec_match_list_free(git_pathspec_match_list *m)
680{
2b672d5b
RB
681 if (m)
682 pathspec_match_free(m);
d2ce27dd
RB
683}
684
685size_t git_pathspec_match_list_entrycount(
686 const git_pathspec_match_list *m)
687{
2b672d5b 688 return m ? git_array_size(m->matches) : 0;
d2ce27dd
RB
689}
690
691const char *git_pathspec_match_list_entry(
692 const git_pathspec_match_list *m, size_t pos)
693{
2b672d5b
RB
694 if (!m || m->datatype != PATHSPEC_DATATYPE_STRINGS ||
695 !git_array_valid_index(m->matches, pos))
696 return NULL;
697
698 return *((const char **)git_array_get(m->matches, pos));
699}
700
701const git_diff_delta *git_pathspec_match_list_diff_entry(
702 const git_pathspec_match_list *m, size_t pos)
703{
704 if (!m || m->datatype != PATHSPEC_DATATYPE_DIFF ||
705 !git_array_valid_index(m->matches, pos))
706 return NULL;
707
708 return *((const git_diff_delta **)git_array_get(m->matches, pos));
d2ce27dd
RB
709}
710
711size_t git_pathspec_match_list_failed_entrycount(
712 const git_pathspec_match_list *m)
713{
2b672d5b 714 return m ? git_array_size(m->failures) : 0;
d2ce27dd
RB
715}
716
717const char * git_pathspec_match_list_failed_entry(
718 const git_pathspec_match_list *m, size_t pos)
e91f9a8f 719{
2b672d5b
RB
720 char **entry = m ? git_array_get(m->failures, pos) : NULL;
721
d2ce27dd 722 return entry ? *entry : NULL;
e91f9a8f 723}
2b672d5b 724