File Coverage

deps/libgit2/src/pathspec.c
Criterion Covered Total %
statement 250 349 71.6
branch 146 296 49.3
condition n/a
subroutine n/a
pod n/a
total 396 645 61.4


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