2 * Copyright (C) 2009-2012 the libgit2 contributors
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.
12 #include "git2/submodule.h"
15 #define ITERATOR_SET_CB(P,NAME_LC) do { \
16 (P)->cb.current = NAME_LC ## _iterator__current; \
17 (P)->cb.at_end = NAME_LC ## _iterator__at_end; \
18 (P)->cb.advance = NAME_LC ## _iterator__advance; \
19 (P)->cb.seek = NAME_LC ## _iterator__seek; \
20 (P)->cb.reset = NAME_LC ## _iterator__reset; \
21 (P)->cb.free = NAME_LC ## _iterator__free; \
24 #define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC) do { \
25 (P) = git__calloc(1, sizeof(NAME_LC ## _iterator)); \
26 GITERR_CHECK_ALLOC(P); \
27 (P)->base.type = GIT_ITERATOR_ ## NAME_UC; \
28 (P)->base.cb = &(P)->cb; \
29 ITERATOR_SET_CB(P,NAME_LC); \
30 (P)->base.start = start ? git__strdup(start) : NULL; \
31 (P)->base.end = end ? git__strdup(end) : NULL; \
32 (P)->base.ignore_case = false; \
33 if ((start && !(P)->base.start) || (end && !(P)->base.end)) \
37 static int iterator__reset_range(
38 git_iterator
*iter
, const char *start
, const char *end
)
42 git__free(iter
->start
);
43 iter
->start
= git__strdup(start
);
44 GITERR_CHECK_ALLOC(iter
->start
);
50 iter
->end
= git__strdup(end
);
51 GITERR_CHECK_ALLOC(iter
->end
);
57 static int empty_iterator__no_item(
58 git_iterator
*iter
, const git_index_entry
**entry
)
65 static int empty_iterator__at_end(git_iterator
*iter
)
71 static int empty_iterator__reset(
72 git_iterator
*iter
, const char *start
, const char *end
)
74 GIT_UNUSED(iter
); GIT_UNUSED(start
); GIT_UNUSED(end
);
78 static int empty_iterator__seek(git_iterator
*iter
, const char *prefix
)
80 GIT_UNUSED(iter
); GIT_UNUSED(prefix
);
84 static void empty_iterator__free(git_iterator
*iter
)
91 git_iterator_callbacks cb
;
94 int git_iterator_for_nothing(git_iterator
**iter
)
96 empty_iterator
*i
= git__calloc(1, sizeof(empty_iterator
));
97 GITERR_CHECK_ALLOC(i
);
99 i
->base
.type
= GIT_ITERATOR_EMPTY
;
101 i
->cb
.current
= empty_iterator__no_item
;
102 i
->cb
.at_end
= empty_iterator__at_end
;
103 i
->cb
.advance
= empty_iterator__no_item
;
104 i
->cb
.seek
= empty_iterator__seek
;
105 i
->cb
.reset
= empty_iterator__reset
;
106 i
->cb
.free
= empty_iterator__free
;
108 *iter
= (git_iterator
*)i
;
114 typedef struct tree_iterator_frame tree_iterator_frame
;
115 struct tree_iterator_frame
{
116 tree_iterator_frame
*next
, *prev
;
124 git_iterator_callbacks cb
;
125 tree_iterator_frame
*stack
, *tail
;
126 git_index_entry entry
;
128 bool path_has_filename
;
131 GIT_INLINE(const git_tree_entry
*)tree_iterator__tree_entry(tree_iterator
*ti
)
133 return git_tree_entry_byindex(ti
->stack
->tree
, ti
->stack
->index
);
136 static char *tree_iterator__current_filename(
137 tree_iterator
*ti
, const git_tree_entry
*te
)
139 if (!ti
->path_has_filename
) {
140 if (git_buf_joinpath(&ti
->path
, ti
->path
.ptr
, te
->filename
) < 0)
142 ti
->path_has_filename
= true;
148 static void tree_iterator__free_frame(tree_iterator_frame
*tf
)
152 git_tree_free(tf
->tree
);
156 static bool tree_iterator__pop_frame(tree_iterator
*ti
)
158 tree_iterator_frame
*tf
= ti
->stack
;
160 /* don't free the initial tree/frame */
164 ti
->stack
= tf
->next
;
165 ti
->stack
->prev
= NULL
;
167 tree_iterator__free_frame(tf
);
172 static int tree_iterator__to_end(tree_iterator
*ti
)
174 while (tree_iterator__pop_frame(ti
)) /* pop all */;
175 ti
->stack
->index
= git_tree_entrycount(ti
->stack
->tree
);
179 static int tree_iterator__current(
180 git_iterator
*self
, const git_index_entry
**entry
)
182 tree_iterator
*ti
= (tree_iterator
*)self
;
183 const git_tree_entry
*te
= tree_iterator__tree_entry(ti
);
191 ti
->entry
.mode
= te
->attr
;
192 git_oid_cpy(&ti
->entry
.oid
, &te
->oid
);
194 ti
->entry
.path
= tree_iterator__current_filename(ti
, te
);
195 if (ti
->entry
.path
== NULL
)
198 if (ti
->base
.end
&& git__prefixcmp(ti
->entry
.path
, ti
->base
.end
) > 0)
199 return tree_iterator__to_end(ti
);
207 static int tree_iterator__at_end(git_iterator
*self
)
209 return (tree_iterator__tree_entry((tree_iterator
*)self
) == NULL
);
212 static tree_iterator_frame
*tree_iterator__alloc_frame(
213 git_tree
*tree
, char *start
)
215 tree_iterator_frame
*tf
= git__calloc(1, sizeof(tree_iterator_frame
));
221 if (start
&& *start
) {
223 tf
->index
= git_tree__prefix_position(tree
, start
);
229 static int tree_iterator__expand_tree(tree_iterator
*ti
)
233 const git_tree_entry
*te
= tree_iterator__tree_entry(ti
);
234 tree_iterator_frame
*tf
;
237 while (te
!= NULL
&& git_tree_entry__is_tree(te
)) {
238 if (git_buf_joinpath(&ti
->path
, ti
->path
.ptr
, te
->filename
) < 0)
241 /* check that we have not passed the range end */
242 if (ti
->base
.end
!= NULL
&&
243 git__prefixcmp(ti
->path
.ptr
, ti
->base
.end
) > 0)
244 return tree_iterator__to_end(ti
);
246 if ((error
= git_tree_lookup(&subtree
, ti
->base
.repo
, &te
->oid
)) < 0)
251 /* apply range start to new frame if relevant */
252 if (ti
->stack
->start
&&
253 git__prefixcmp(ti
->stack
->start
, te
->filename
) == 0)
255 size_t namelen
= strlen(te
->filename
);
256 if (ti
->stack
->start
[namelen
] == '/')
257 relpath
= ti
->stack
->start
+ namelen
+ 1;
260 if ((tf
= tree_iterator__alloc_frame(subtree
, relpath
)) == NULL
)
263 tf
->next
= ti
->stack
;
267 te
= tree_iterator__tree_entry(ti
);
273 static int tree_iterator__advance(
274 git_iterator
*self
, const git_index_entry
**entry
)
277 tree_iterator
*ti
= (tree_iterator
*)self
;
278 const git_tree_entry
*te
= NULL
;
283 if (ti
->path_has_filename
) {
284 git_buf_rtruncate_at_char(&ti
->path
, '/');
285 ti
->path_has_filename
= false;
289 te
= git_tree_entry_byindex(ti
->stack
->tree
, ++ti
->stack
->index
);
293 if (!tree_iterator__pop_frame(ti
))
294 break; /* no frames left to pop */
296 git_buf_rtruncate_at_char(&ti
->path
, '/');
299 if (te
&& git_tree_entry__is_tree(te
))
300 error
= tree_iterator__expand_tree(ti
);
303 error
= tree_iterator__current(self
, entry
);
308 static int tree_iterator__seek(git_iterator
*self
, const char *prefix
)
312 /* pop stack until matches prefix */
313 /* seek item in current frame matching prefix */
314 /* push stack which matches prefix */
318 static void tree_iterator__free(git_iterator
*self
)
320 tree_iterator
*ti
= (tree_iterator
*)self
;
322 while (tree_iterator__pop_frame(ti
)) /* pop all */;
324 tree_iterator__free_frame(ti
->stack
);
325 ti
->stack
= ti
->tail
= NULL
;
327 git_buf_free(&ti
->path
);
330 static int tree_iterator__reset(
331 git_iterator
*self
, const char *start
, const char *end
)
333 tree_iterator
*ti
= (tree_iterator
*)self
;
335 while (tree_iterator__pop_frame(ti
)) /* pop all */;
337 if (iterator__reset_range(self
, start
, end
) < 0)
341 git_tree__prefix_position(ti
->stack
->tree
, ti
->base
.start
);
343 git_buf_clear(&ti
->path
);
344 ti
->path_has_filename
= false;
346 return tree_iterator__expand_tree(ti
);
349 int git_iterator_for_tree_range(
359 return git_iterator_for_nothing(iter
);
361 if ((error
= git_tree__dup(&tree
, tree
)) < 0)
364 ITERATOR_BASE_INIT(ti
, tree
, TREE
);
366 ti
->base
.repo
= git_tree_owner(tree
);
367 ti
->stack
= ti
->tail
= tree_iterator__alloc_frame(tree
, ti
->base
.start
);
369 if ((error
= tree_iterator__expand_tree(ti
)) < 0)
370 git_iterator_free((git_iterator
*)ti
);
372 *iter
= (git_iterator
*)ti
;
380 git_iterator_callbacks cb
;
385 static int index_iterator__current(
386 git_iterator
*self
, const git_index_entry
**entry
)
388 index_iterator
*ii
= (index_iterator
*)self
;
389 const git_index_entry
*ie
= git_index_get_byindex(ii
->index
, ii
->current
);
397 static int index_iterator__at_end(git_iterator
*self
)
399 index_iterator
*ii
= (index_iterator
*)self
;
400 return (ii
->current
>= git_index_entrycount(ii
->index
));
403 static void index_iterator__skip_conflicts(
406 size_t entrycount
= git_index_entrycount(ii
->index
);
407 const git_index_entry
*ie
;
409 while (ii
->current
< entrycount
) {
410 ie
= git_index_get_byindex(ii
->index
, ii
->current
);
413 (ii
->base
.end
!= NULL
&&
414 ITERATOR_PREFIXCMP(ii
->base
, ie
->path
, ii
->base
.end
) > 0)) {
415 ii
->current
= entrycount
;
419 if (git_index_entry_stage(ie
) == 0)
426 static int index_iterator__advance(
427 git_iterator
*self
, const git_index_entry
**entry
)
429 index_iterator
*ii
= (index_iterator
*)self
;
431 if (ii
->current
< git_index_entrycount(ii
->index
))
434 index_iterator__skip_conflicts(ii
);
436 return index_iterator__current(self
, entry
);
439 static int index_iterator__seek(git_iterator
*self
, const char *prefix
)
443 /* find last item before prefix */
447 static int index_iterator__reset(
448 git_iterator
*self
, const char *start
, const char *end
)
450 index_iterator
*ii
= (index_iterator
*)self
;
451 if (iterator__reset_range(self
, start
, end
) < 0)
453 ii
->current
= ii
->base
.start
?
454 git_index__prefix_position(ii
->index
, ii
->base
.start
) : 0;
455 index_iterator__skip_conflicts(ii
);
459 static void index_iterator__free(git_iterator
*self
)
461 index_iterator
*ii
= (index_iterator
*)self
;
462 git_index_free(ii
->index
);
466 int git_iterator_for_index_range(
474 ITERATOR_BASE_INIT(ii
, index
, INDEX
);
476 ii
->base
.repo
= git_index_owner(index
);
477 ii
->base
.ignore_case
= index
->ignore_case
;
479 GIT_REFCOUNT_INC(index
);
481 index_iterator__reset((git_iterator
*)ii
, NULL
, NULL
);
483 *iter
= (git_iterator
*)ii
;
488 int git_iterator_for_repo_index_range(
490 git_repository
*repo
,
497 if ((error
= git_repository_index__weakptr(&index
, repo
)) < 0)
500 return git_iterator_for_index_range(iter
, index
, start
, end
);
503 typedef struct workdir_iterator_frame workdir_iterator_frame
;
504 struct workdir_iterator_frame
{
505 workdir_iterator_frame
*next
;
512 git_iterator_callbacks cb
;
513 workdir_iterator_frame
*stack
;
514 int (*entrycmp
)(const void *pfx
, const void *item
);
516 git_index_entry entry
;
522 GIT_INLINE(bool) path_is_dotgit(const git_path_with_stat
*ps
)
527 const char *path
= ps
->path
;
528 size_t len
= ps
->path_len
;
532 if (path
[len
- 1] == '/')
534 if (tolower(path
[len
- 1]) != 't' ||
535 tolower(path
[len
- 2]) != 'i' ||
536 tolower(path
[len
- 3]) != 'g' ||
537 tolower(path
[len
- 4]) != '.')
539 return (len
== 4 || path
[len
- 5] == '/');
543 static workdir_iterator_frame
*workdir_iterator__alloc_frame(
544 workdir_iterator
*wi
)
546 workdir_iterator_frame
*wf
= git__calloc(1, sizeof(workdir_iterator_frame
));
547 git_vector_cmp entry_compare
= CASESELECT(wi
->base
.ignore_case
,
548 git_path_with_stat_cmp_icase
, git_path_with_stat_cmp
);
553 if (git_vector_init(&wf
->entries
, 0, entry_compare
) != 0) {
561 static void workdir_iterator__free_frame(workdir_iterator_frame
*wf
)
564 git_path_with_stat
*path
;
566 git_vector_foreach(&wf
->entries
, i
, path
)
568 git_vector_free(&wf
->entries
);
572 static int workdir_iterator__update_entry(workdir_iterator
*wi
);
574 static int workdir_iterator__entry_cmp_case(const void *pfx
, const void *item
)
576 const git_path_with_stat
*ps
= item
;
577 return git__prefixcmp((const char *)pfx
, ps
->path
);
580 static int workdir_iterator__entry_cmp_icase(const void *pfx
, const void *item
)
582 const git_path_with_stat
*ps
= item
;
583 return git__prefixcmp_icase((const char *)pfx
, ps
->path
);
586 static void workdir_iterator__seek_frame_start(
587 workdir_iterator
*wi
, workdir_iterator_frame
*wf
)
594 &wf
->index
, &wf
->entries
, wi
->entrycmp
, wi
->base
.start
);
598 if (path_is_dotgit(git_vector_get(&wf
->entries
, wf
->index
)))
602 static int workdir_iterator__expand_dir(workdir_iterator
*wi
)
605 workdir_iterator_frame
*wf
= workdir_iterator__alloc_frame(wi
);
606 GITERR_CHECK_ALLOC(wf
);
608 error
= git_path_dirload_with_stat(
609 wi
->path
.ptr
, wi
->root_len
, wi
->base
.ignore_case
,
610 wi
->base
.start
, wi
->base
.end
, &wf
->entries
);
612 if (error
< 0 || wf
->entries
.length
== 0) {
613 workdir_iterator__free_frame(wf
);
614 return GIT_ENOTFOUND
;
617 workdir_iterator__seek_frame_start(wi
, wf
);
619 /* only push new ignores if this is not top level directory */
620 if (wi
->stack
!= NULL
) {
621 ssize_t slash_pos
= git_buf_rfind_next(&wi
->path
, '/');
622 (void)git_ignore__push_dir(&wi
->ignores
, &wi
->path
.ptr
[slash_pos
+ 1]);
625 wf
->next
= wi
->stack
;
628 return workdir_iterator__update_entry(wi
);
631 static int workdir_iterator__current(
632 git_iterator
*self
, const git_index_entry
**entry
)
634 workdir_iterator
*wi
= (workdir_iterator
*)self
;
635 *entry
= (wi
->entry
.path
== NULL
) ? NULL
: &wi
->entry
;
639 static int workdir_iterator__at_end(git_iterator
*self
)
641 return (((workdir_iterator
*)self
)->entry
.path
== NULL
);
644 static int workdir_iterator__advance(
645 git_iterator
*self
, const git_index_entry
**entry
)
648 workdir_iterator
*wi
= (workdir_iterator
*)self
;
649 workdir_iterator_frame
*wf
;
650 git_path_with_stat
*next
;
655 if (wi
->entry
.path
== NULL
)
660 next
= git_vector_get(&wf
->entries
, ++wf
->index
);
663 /* match git's behavior of ignoring anything named ".git" */
664 if (path_is_dotgit(next
))
666 /* else found a good entry */
670 /* pop stack if anything is left to pop */
672 memset(&wi
->entry
, 0, sizeof(wi
->entry
));
676 wi
->stack
= wf
->next
;
677 workdir_iterator__free_frame(wf
);
678 git_ignore__pop_dir(&wi
->ignores
);
681 error
= workdir_iterator__update_entry(wi
);
683 if (!error
&& entry
!= NULL
)
684 error
= workdir_iterator__current(self
, entry
);
689 static int workdir_iterator__seek(git_iterator
*self
, const char *prefix
)
693 /* pop stack until matching prefix */
694 /* find prefix item in current frame */
695 /* push subdirectories as deep as possible while matching */
699 static int workdir_iterator__reset(
700 git_iterator
*self
, const char *start
, const char *end
)
702 workdir_iterator
*wi
= (workdir_iterator
*)self
;
704 while (wi
->stack
!= NULL
&& wi
->stack
->next
!= NULL
) {
705 workdir_iterator_frame
*wf
= wi
->stack
;
706 wi
->stack
= wf
->next
;
707 workdir_iterator__free_frame(wf
);
708 git_ignore__pop_dir(&wi
->ignores
);
711 if (iterator__reset_range(self
, start
, end
) < 0)
714 workdir_iterator__seek_frame_start(wi
, wi
->stack
);
716 return workdir_iterator__update_entry(wi
);
719 static void workdir_iterator__free(git_iterator
*self
)
721 workdir_iterator
*wi
= (workdir_iterator
*)self
;
723 while (wi
->stack
!= NULL
) {
724 workdir_iterator_frame
*wf
= wi
->stack
;
725 wi
->stack
= wf
->next
;
726 workdir_iterator__free_frame(wf
);
729 git_ignore__free(&wi
->ignores
);
730 git_buf_free(&wi
->path
);
733 static int workdir_iterator__update_entry(workdir_iterator
*wi
)
735 git_path_with_stat
*ps
=
736 git_vector_get(&wi
->stack
->entries
, wi
->stack
->index
);
738 git_buf_truncate(&wi
->path
, wi
->root_len
);
739 memset(&wi
->entry
, 0, sizeof(wi
->entry
));
744 if (git_buf_put(&wi
->path
, ps
->path
, ps
->path_len
) < 0)
747 if (wi
->base
.end
&& ITERATOR_PREFIXCMP(
748 wi
->base
, wi
->path
.ptr
+ wi
->root_len
, wi
->base
.end
) > 0)
751 wi
->entry
.path
= ps
->path
;
753 /* skip over .git entries */
754 if (path_is_dotgit(ps
))
755 return workdir_iterator__advance((git_iterator
*)wi
, NULL
);
759 git_index_entry__init_from_stat(&wi
->entry
, &ps
->st
);
761 /* need different mode here to keep directories during iteration */
762 wi
->entry
.mode
= git_futils_canonical_mode(ps
->st
.st_mode
);
764 /* if this is a file type we don't handle, treat as ignored */
765 if (wi
->entry
.mode
== 0) {
770 /* detect submodules */
771 if (S_ISDIR(wi
->entry
.mode
)) {
772 int res
= git_submodule_lookup(NULL
, wi
->base
.repo
, wi
->entry
.path
);
773 bool is_submodule
= (res
== 0);
774 if (res
== GIT_ENOTFOUND
)
777 /* if submodule, mark as GITLINK and remove trailing slash */
779 size_t len
= strlen(wi
->entry
.path
);
780 assert(wi
->entry
.path
[len
- 1] == '/');
781 wi
->entry
.path
[len
- 1] = '\0';
782 wi
->entry
.mode
= S_IFGITLINK
;
789 int git_iterator_for_workdir_range(
791 git_repository
*repo
,
796 workdir_iterator
*wi
;
799 assert(iter
&& repo
);
801 if ((error
= git_repository__ensure_not_bare(
802 repo
, "scan working directory")) < 0)
805 ITERATOR_BASE_INIT(wi
, workdir
, WORKDIR
);
806 wi
->base
.repo
= repo
;
808 if ((error
= git_repository_index__weakptr(&index
, repo
)) < 0) {
809 git_iterator_free((git_iterator
*)wi
);
813 /* Match ignore_case flag for iterator to that of the index */
814 wi
->base
.ignore_case
= index
->ignore_case
;
816 if (git_buf_sets(&wi
->path
, git_repository_workdir(repo
)) < 0 ||
817 git_path_to_dir(&wi
->path
) < 0 ||
818 git_ignore__for_path(repo
, "", &wi
->ignores
) < 0)
824 wi
->root_len
= wi
->path
.size
;
825 wi
->entrycmp
= wi
->base
.ignore_case
?
826 workdir_iterator__entry_cmp_icase
: workdir_iterator__entry_cmp_case
;
828 if ((error
= workdir_iterator__expand_dir(wi
)) < 0) {
829 if (error
== GIT_ENOTFOUND
)
832 git_iterator_free((git_iterator
*)wi
);
837 *iter
= (git_iterator
*)wi
;
843 /* replacement callbacks */
844 git_iterator_callbacks cb
;
845 /* original iterator values */
846 git_iterator_callbacks
*orig
;
847 git_iterator_type_t orig_type
;
848 /* spoolandsort data */
851 git_pool string_pool
;
853 } spoolandsort_callbacks
;
855 static int spoolandsort_iterator__current(
856 git_iterator
*self
, const git_index_entry
**entry
)
858 spoolandsort_callbacks
*scb
= (spoolandsort_callbacks
*)self
->cb
;
860 *entry
= (const git_index_entry
*)
861 git_vector_get(&scb
->entries
, scb
->position
);
866 static int spoolandsort_iterator__at_end(git_iterator
*self
)
868 spoolandsort_callbacks
*scb
= (spoolandsort_callbacks
*)self
->cb
;
870 return 0 == scb
->entries
.length
|| scb
->entries
.length
- 1 <= scb
->position
;
873 static int spoolandsort_iterator__advance(
874 git_iterator
*self
, const git_index_entry
**entry
)
876 spoolandsort_callbacks
*scb
= (spoolandsort_callbacks
*)self
->cb
;
878 *entry
= (const git_index_entry
*)
879 git_vector_get(&scb
->entries
, ++scb
->position
);
884 static int spoolandsort_iterator__seek(git_iterator
*self
, const char *prefix
)
892 static int spoolandsort_iterator__reset(
893 git_iterator
*self
, const char *start
, const char *end
)
895 spoolandsort_callbacks
*scb
= (spoolandsort_callbacks
*)self
->cb
;
897 GIT_UNUSED(start
); GIT_UNUSED(end
);
904 static void spoolandsort_iterator__free_callbacks(spoolandsort_callbacks
*scb
)
906 git_pool_clear(&scb
->string_pool
);
907 git_pool_clear(&scb
->entry_pool
);
908 git_vector_free(&scb
->entries
);
912 void git_iterator_spoolandsort_pop(git_iterator
*self
)
914 spoolandsort_callbacks
*scb
= (spoolandsort_callbacks
*)self
->cb
;
916 if (self
->type
!= GIT_ITERATOR_SPOOLANDSORT
)
919 self
->cb
= scb
->orig
;
920 self
->type
= scb
->orig_type
;
921 self
->ignore_case
= !self
->ignore_case
;
923 spoolandsort_iterator__free_callbacks(scb
);
926 static void spoolandsort_iterator__free(git_iterator
*self
)
928 git_iterator_spoolandsort_pop(self
);
929 self
->cb
->free(self
);
932 int git_iterator_spoolandsort_push(git_iterator
*iter
, bool ignore_case
)
934 const git_index_entry
*item
;
935 spoolandsort_callbacks
*scb
;
936 int (*entrycomp
)(const void *a
, const void *b
);
938 if (iter
->ignore_case
== ignore_case
)
941 scb
= git__calloc(1, sizeof(spoolandsort_callbacks
));
942 GITERR_CHECK_ALLOC(scb
);
944 ITERATOR_SET_CB(scb
,spoolandsort
);
946 scb
->orig
= iter
->cb
;
947 scb
->orig_type
= iter
->type
;
950 entrycomp
= ignore_case
? git_index_entry__cmp_icase
: git_index_entry__cmp
;
952 if (git_vector_init(&scb
->entries
, 16, entrycomp
) < 0 ||
953 git_pool_init(&scb
->entry_pool
, sizeof(git_index_entry
), 0) < 0 ||
954 git_pool_init(&scb
->string_pool
, 1, 0) < 0 ||
955 git_iterator_current(iter
, &item
) < 0)
959 git_index_entry
*clone
= git_pool_malloc(&scb
->entry_pool
, 1);
963 memcpy(clone
, item
, sizeof(git_index_entry
));
966 clone
->path
= git_pool_strdup(&scb
->string_pool
, item
->path
);
971 if (git_vector_insert(&scb
->entries
, clone
) < 0)
974 if (git_iterator_advance(iter
, &item
) < 0)
978 git_vector_sort(&scb
->entries
);
980 iter
->cb
= (git_iterator_callbacks
*)scb
;
981 iter
->type
= GIT_ITERATOR_SPOOLANDSORT
;
982 iter
->ignore_case
= !iter
->ignore_case
;
987 spoolandsort_iterator__free_callbacks(scb
);
991 int git_iterator_current_tree_entry(
992 git_iterator
*iter
, const git_tree_entry
**tree_entry
)
994 *tree_entry
= (iter
->type
!= GIT_ITERATOR_TREE
) ? NULL
:
995 tree_iterator__tree_entry((tree_iterator
*)iter
);
999 int git_iterator_current_parent_tree(
1001 const char *parent_path
,
1002 const git_tree
**tree_ptr
)
1004 tree_iterator
*ti
= (tree_iterator
*)iter
;
1005 tree_iterator_frame
*tf
;
1006 const char *scan
= parent_path
;
1008 if (iter
->type
!= GIT_ITERATOR_TREE
|| ti
->stack
== NULL
)
1011 for (tf
= ti
->tail
; tf
!= NULL
; tf
= tf
->prev
) {
1012 const git_tree_entry
*te
;
1015 *tree_ptr
= tf
->tree
;
1019 te
= git_tree_entry_byindex(tf
->tree
, tf
->index
);
1021 if (strncmp(scan
, te
->filename
, te
->filename_len
) != 0)
1024 scan
+= te
->filename_len
;
1038 int git_iterator_current_is_ignored(git_iterator
*iter
)
1040 workdir_iterator
*wi
= (workdir_iterator
*)iter
;
1042 if (iter
->type
!= GIT_ITERATOR_WORKDIR
)
1045 if (wi
->is_ignored
!= -1)
1046 return wi
->is_ignored
;
1048 if (git_ignore__lookup(&wi
->ignores
, wi
->entry
.path
, &wi
->is_ignored
) < 0)
1051 return wi
->is_ignored
;
1054 int git_iterator_advance_into_directory(
1055 git_iterator
*iter
, const git_index_entry
**entry
)
1057 workdir_iterator
*wi
= (workdir_iterator
*)iter
;
1059 if (iter
->type
== GIT_ITERATOR_WORKDIR
&&
1061 S_ISDIR(wi
->entry
.mode
) &&
1062 !S_ISGITLINK(wi
->entry
.mode
))
1064 if (workdir_iterator__expand_dir(wi
) < 0)
1065 /* if error loading or if empty, skip the directory. */
1066 return workdir_iterator__advance(iter
, entry
);
1069 return entry
? git_iterator_current(iter
, entry
) : 0;
1072 int git_iterator_cmp(
1073 git_iterator
*iter
, const char *path_prefix
)
1075 const git_index_entry
*entry
;
1077 /* a "done" iterator is after every prefix */
1078 if (git_iterator_current(iter
, &entry
) < 0 ||
1082 /* a NULL prefix is after any valid iterator */
1086 return ITERATOR_PREFIXCMP(*iter
, entry
->path
, path_prefix
);
1089 int git_iterator_current_workdir_path(git_iterator
*iter
, git_buf
**path
)
1091 workdir_iterator
*wi
= (workdir_iterator
*)iter
;
1093 if (iter
->type
!= GIT_ITERATOR_WORKDIR
|| !wi
->entry
.path
)