mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-11 17:41:55 +00:00
Merge pull request #1211 from arrbee/fix-icase-status-file
Fix case insensitivity issues in git_status_file
This commit is contained in:
commit
34a4ad46e8
@ -208,6 +208,15 @@ GIT_EXTERN(git_otype) git_tree_entry_type(const git_tree_entry *entry);
|
|||||||
*/
|
*/
|
||||||
GIT_EXTERN(git_filemode_t) git_tree_entry_filemode(const git_tree_entry *entry);
|
GIT_EXTERN(git_filemode_t) git_tree_entry_filemode(const git_tree_entry *entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two tree entries
|
||||||
|
*
|
||||||
|
* @param e1 first tree entry
|
||||||
|
* @param e2 second tree entry
|
||||||
|
* @return <0 if e1 is before e2, 0 if e1 == e2, >0 if e1 is after e2
|
||||||
|
*/
|
||||||
|
GIT_EXTERN(int) git_tree_entry_cmp(const git_tree_entry *e1, const git_tree_entry *e2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a tree entry to the git_object it points too.
|
* Convert a tree entry to the git_object it points too.
|
||||||
*
|
*
|
||||||
|
@ -224,7 +224,7 @@ static int checkout_action_wd_only(
|
|||||||
if (!git_pathspec_match_path(
|
if (!git_pathspec_match_path(
|
||||||
pathspec, wd->path,
|
pathspec, wd->path,
|
||||||
(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
|
(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
|
||||||
workdir->ignore_case))
|
git_iterator_ignore_case(workdir)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* check if item is tracked in the index but not in the checkout diff */
|
/* check if item is tracked in the index but not in the checkout diff */
|
||||||
@ -1130,7 +1130,7 @@ static int checkout_data_init(
|
|||||||
if ((error = git_config_refresh(cfg)) < 0)
|
if ((error = git_config_refresh(cfg)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (git_iterator_inner_type(target) == GIT_ITERATOR_INDEX) {
|
if (git_iterator_inner_type(target) == GIT_ITERATOR_TYPE_INDEX) {
|
||||||
/* if we are iterating over the index, don't reload */
|
/* if we are iterating over the index, don't reload */
|
||||||
data->index = git_iterator_index_get_index(target);
|
data->index = git_iterator_index_get_index(target);
|
||||||
GIT_REFCOUNT_INC(data->index);
|
GIT_REFCOUNT_INC(data->index);
|
||||||
@ -1208,6 +1208,7 @@ int git_checkout_iterator(
|
|||||||
git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
|
git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
|
||||||
uint32_t *actions = NULL;
|
uint32_t *actions = NULL;
|
||||||
size_t *counts = NULL;
|
size_t *counts = NULL;
|
||||||
|
git_iterator_flag_t iterflags = 0;
|
||||||
|
|
||||||
/* initialize structures and options */
|
/* initialize structures and options */
|
||||||
error = checkout_data_init(&data, target, opts);
|
error = checkout_data_init(&data, target, opts);
|
||||||
@ -1228,18 +1229,21 @@ int git_checkout_iterator(
|
|||||||
diff_opts.pathspec = data.opts.paths;
|
diff_opts.pathspec = data.opts.paths;
|
||||||
|
|
||||||
/* set up iterators */
|
/* set up iterators */
|
||||||
|
|
||||||
|
iterflags = git_iterator_ignore_case(target) ?
|
||||||
|
GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE;
|
||||||
|
|
||||||
if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 ||
|
if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 ||
|
||||||
(error = git_iterator_for_workdir_range(
|
(error = git_iterator_for_workdir_range(
|
||||||
&workdir, data.repo, data.pfx, data.pfx)) < 0 ||
|
&workdir, data.repo, iterflags, data.pfx, data.pfx)) < 0 ||
|
||||||
(error = git_iterator_for_tree_range(
|
(error = git_iterator_for_tree_range(
|
||||||
&baseline, data.opts.baseline, data.pfx, data.pfx)) < 0)
|
&baseline, data.opts.baseline, iterflags, data.pfx, data.pfx)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* Handle case insensitivity for baseline if necessary */
|
/* Handle case insensitivity for baseline if necessary */
|
||||||
if (workdir->ignore_case && !baseline->ignore_case) {
|
if (git_iterator_ignore_case(workdir) != git_iterator_ignore_case(baseline))
|
||||||
if ((error = git_iterator_spoolandsort_push(baseline, true)) < 0)
|
if ((error = git_iterator_spoolandsort_push(baseline, true)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate baseline-to-target diff which will include an entry for
|
/* Generate baseline-to-target diff which will include an entry for
|
||||||
* every possible update that might need to be made.
|
* every possible update that might need to be made.
|
||||||
|
24
src/diff.c
24
src/diff.c
@ -418,7 +418,7 @@ static int maybe_modified(
|
|||||||
git_delta_t status = GIT_DELTA_MODIFIED;
|
git_delta_t status = GIT_DELTA_MODIFIED;
|
||||||
unsigned int omode = oitem->mode;
|
unsigned int omode = oitem->mode;
|
||||||
unsigned int nmode = nitem->mode;
|
unsigned int nmode = nitem->mode;
|
||||||
bool new_is_workdir = (new_iter->type == GIT_ITERATOR_WORKDIR);
|
bool new_is_workdir = (new_iter->type == GIT_ITERATOR_TYPE_WORKDIR);
|
||||||
|
|
||||||
GIT_UNUSED(old_iter);
|
GIT_UNUSED(old_iter);
|
||||||
|
|
||||||
@ -556,7 +556,9 @@ static int diff_list_init_from_iterators(
|
|||||||
|
|
||||||
/* Use case-insensitive compare if either iterator has
|
/* Use case-insensitive compare if either iterator has
|
||||||
* the ignore_case bit set */
|
* the ignore_case bit set */
|
||||||
if (!old_iter->ignore_case && !new_iter->ignore_case) {
|
if (!git_iterator_ignore_case(old_iter) &&
|
||||||
|
!git_iterator_ignore_case(new_iter))
|
||||||
|
{
|
||||||
diff->opts.flags &= ~GIT_DIFF_DELTAS_ARE_ICASE;
|
diff->opts.flags &= ~GIT_DIFF_DELTAS_ARE_ICASE;
|
||||||
|
|
||||||
diff->strcomp = git__strcmp;
|
diff->strcomp = git__strcmp;
|
||||||
@ -714,7 +716,7 @@ int git_diff__from_iterators(
|
|||||||
else if (git_iterator_current_is_ignored(new_iter))
|
else if (git_iterator_current_is_ignored(new_iter))
|
||||||
delta_type = GIT_DELTA_IGNORED;
|
delta_type = GIT_DELTA_IGNORED;
|
||||||
|
|
||||||
else if (new_iter->type != GIT_ITERATOR_WORKDIR)
|
else if (new_iter->type != GIT_ITERATOR_TYPE_WORKDIR)
|
||||||
delta_type = GIT_DELTA_ADDED;
|
delta_type = GIT_DELTA_ADDED;
|
||||||
|
|
||||||
if (diff_delta__from_one(diff, delta_type, nitem) < 0)
|
if (diff_delta__from_one(diff, delta_type, nitem) < 0)
|
||||||
@ -786,8 +788,8 @@ int git_diff_tree_to_tree(
|
|||||||
assert(diff && repo);
|
assert(diff && repo);
|
||||||
|
|
||||||
DIFF_FROM_ITERATORS(
|
DIFF_FROM_ITERATORS(
|
||||||
git_iterator_for_tree_range(&a, old_tree, pfx, pfx),
|
git_iterator_for_tree_range(&a, old_tree, 0, pfx, pfx),
|
||||||
git_iterator_for_tree_range(&b, new_tree, pfx, pfx)
|
git_iterator_for_tree_range(&b, new_tree, 0, pfx, pfx)
|
||||||
);
|
);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
@ -808,8 +810,8 @@ int git_diff_tree_to_index(
|
|||||||
return error;
|
return error;
|
||||||
|
|
||||||
DIFF_FROM_ITERATORS(
|
DIFF_FROM_ITERATORS(
|
||||||
git_iterator_for_tree_range(&a, old_tree, pfx, pfx),
|
git_iterator_for_tree_range(&a, old_tree, 0, pfx, pfx),
|
||||||
git_iterator_for_index_range(&b, index, pfx, pfx)
|
git_iterator_for_index_range(&b, index, 0, pfx, pfx)
|
||||||
);
|
);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
@ -829,8 +831,8 @@ int git_diff_index_to_workdir(
|
|||||||
return error;
|
return error;
|
||||||
|
|
||||||
DIFF_FROM_ITERATORS(
|
DIFF_FROM_ITERATORS(
|
||||||
git_iterator_for_index_range(&a, index, pfx, pfx),
|
git_iterator_for_index_range(&a, index, 0, pfx, pfx),
|
||||||
git_iterator_for_workdir_range(&b, repo, pfx, pfx)
|
git_iterator_for_workdir_range(&b, repo, 0, pfx, pfx)
|
||||||
);
|
);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
@ -848,8 +850,8 @@ int git_diff_tree_to_workdir(
|
|||||||
assert(diff && repo);
|
assert(diff && repo);
|
||||||
|
|
||||||
DIFF_FROM_ITERATORS(
|
DIFF_FROM_ITERATORS(
|
||||||
git_iterator_for_tree_range(&a, old_tree, pfx, pfx),
|
git_iterator_for_tree_range(&a, old_tree, 0, pfx, pfx),
|
||||||
git_iterator_for_workdir_range(&b, repo, pfx, pfx)
|
git_iterator_for_workdir_range(&b, repo, 0, pfx, pfx)
|
||||||
);
|
);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
@ -495,7 +495,7 @@ static void diff_patch_init(
|
|||||||
patch->old_src = patch->diff->old_src;
|
patch->old_src = patch->diff->old_src;
|
||||||
patch->new_src = patch->diff->new_src;
|
patch->new_src = patch->diff->new_src;
|
||||||
} else {
|
} else {
|
||||||
patch->old_src = patch->new_src = GIT_ITERATOR_TREE;
|
patch->old_src = patch->new_src = GIT_ITERATOR_TYPE_TREE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,7 +578,7 @@ static int diff_patch_load(
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if ((delta->old_file.flags & GIT_DIFF_FILE_NO_DATA) == 0 &&
|
if ((delta->old_file.flags & GIT_DIFF_FILE_NO_DATA) == 0 &&
|
||||||
patch->old_src == GIT_ITERATOR_WORKDIR) {
|
patch->old_src == GIT_ITERATOR_TYPE_WORKDIR) {
|
||||||
if ((error = get_workdir_content(
|
if ((error = get_workdir_content(
|
||||||
ctxt, delta, &delta->old_file, &patch->old_data)) < 0)
|
ctxt, delta, &delta->old_file, &patch->old_data)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -587,7 +587,7 @@ static int diff_patch_load(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((delta->new_file.flags & GIT_DIFF_FILE_NO_DATA) == 0 &&
|
if ((delta->new_file.flags & GIT_DIFF_FILE_NO_DATA) == 0 &&
|
||||||
patch->new_src == GIT_ITERATOR_WORKDIR) {
|
patch->new_src == GIT_ITERATOR_TYPE_WORKDIR) {
|
||||||
if ((error = get_workdir_content(
|
if ((error = get_workdir_content(
|
||||||
ctxt, delta, &delta->new_file, &patch->new_data)) < 0)
|
ctxt, delta, &delta->new_file, &patch->new_data)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -596,7 +596,7 @@ static int diff_patch_load(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((delta->old_file.flags & GIT_DIFF_FILE_NO_DATA) == 0 &&
|
if ((delta->old_file.flags & GIT_DIFF_FILE_NO_DATA) == 0 &&
|
||||||
patch->old_src != GIT_ITERATOR_WORKDIR) {
|
patch->old_src != GIT_ITERATOR_TYPE_WORKDIR) {
|
||||||
if ((error = get_blob_content(
|
if ((error = get_blob_content(
|
||||||
ctxt, delta, &delta->old_file,
|
ctxt, delta, &delta->old_file,
|
||||||
&patch->old_data, &patch->old_blob)) < 0)
|
&patch->old_data, &patch->old_blob)) < 0)
|
||||||
@ -606,7 +606,7 @@ static int diff_patch_load(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((delta->new_file.flags & GIT_DIFF_FILE_NO_DATA) == 0 &&
|
if ((delta->new_file.flags & GIT_DIFF_FILE_NO_DATA) == 0 &&
|
||||||
patch->new_src != GIT_ITERATOR_WORKDIR) {
|
patch->new_src != GIT_ITERATOR_TYPE_WORKDIR) {
|
||||||
if ((error = get_blob_content(
|
if ((error = get_blob_content(
|
||||||
ctxt, delta, &delta->new_file,
|
ctxt, delta, &delta->new_file,
|
||||||
&patch->new_data, &patch->new_blob)) < 0)
|
&patch->new_data, &patch->new_blob)) < 0)
|
||||||
@ -1666,32 +1666,28 @@ int git_diff__paired_foreach(
|
|||||||
int cmp;
|
int cmp;
|
||||||
git_diff_delta *i2h, *w2i;
|
git_diff_delta *i2h, *w2i;
|
||||||
size_t i, j, i_max, j_max;
|
size_t i, j, i_max, j_max;
|
||||||
bool icase = false;
|
int (*strcomp)(const char *, const char *);
|
||||||
|
|
||||||
i_max = idx2head ? idx2head->deltas.length : 0;
|
i_max = idx2head ? idx2head->deltas.length : 0;
|
||||||
j_max = wd2idx ? wd2idx->deltas.length : 0;
|
j_max = wd2idx ? wd2idx->deltas.length : 0;
|
||||||
|
|
||||||
if (idx2head && wd2idx &&
|
/* Get appropriate strcmp function */
|
||||||
(0 != (idx2head->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) ||
|
strcomp = idx2head ? idx2head->strcomp : wd2idx ? wd2idx->strcomp : NULL;
|
||||||
0 != (wd2idx->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE)))
|
|
||||||
{
|
|
||||||
/* Then use the ignore-case sorter... */
|
|
||||||
icase = true;
|
|
||||||
|
|
||||||
/* and assert that both are ignore-case sorted. If this function
|
/* Assert both iterators use matching ignore-case. If this function ever
|
||||||
* ever needs to support merge joining result sets that are not sorted
|
* supports merging diffs that are not sorted by the same function, then
|
||||||
* by the same function, then it will need to be extended to do a spool
|
* it will need to spool and sort on one of the results before merging
|
||||||
* and sort on one of the results before merge joining */
|
*/
|
||||||
assert(0 != (idx2head->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE) &&
|
if (idx2head && wd2idx) {
|
||||||
0 != (wd2idx->opts.flags & GIT_DIFF_DELTAS_ARE_ICASE));
|
assert(idx2head->strcomp == wd2idx->strcomp);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0, j = 0; i < i_max || j < j_max; ) {
|
for (i = 0, j = 0; i < i_max || j < j_max; ) {
|
||||||
i2h = idx2head ? GIT_VECTOR_GET(&idx2head->deltas,i) : NULL;
|
i2h = idx2head ? GIT_VECTOR_GET(&idx2head->deltas,i) : NULL;
|
||||||
w2i = wd2idx ? GIT_VECTOR_GET(&wd2idx->deltas,j) : NULL;
|
w2i = wd2idx ? GIT_VECTOR_GET(&wd2idx->deltas,j) : NULL;
|
||||||
|
|
||||||
cmp = !w2i ? -1 : !i2h ? 1 :
|
cmp = !w2i ? -1 : !i2h ? 1 :
|
||||||
STRCMP_CASESELECT(icase, i2h->old_file.path, w2i->old_file.path);
|
strcomp(i2h->old_file.path, w2i->old_file.path);
|
||||||
|
|
||||||
if (cmp < 0) {
|
if (cmp < 0) {
|
||||||
if (cb(i2h, NULL, payload))
|
if (cb(i2h, NULL, payload))
|
||||||
|
277
src/iterator.c
277
src/iterator.c
@ -24,14 +24,14 @@
|
|||||||
#define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC) do { \
|
#define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC) do { \
|
||||||
(P) = git__calloc(1, sizeof(NAME_LC ## _iterator)); \
|
(P) = git__calloc(1, sizeof(NAME_LC ## _iterator)); \
|
||||||
GITERR_CHECK_ALLOC(P); \
|
GITERR_CHECK_ALLOC(P); \
|
||||||
(P)->base.type = GIT_ITERATOR_ ## NAME_UC; \
|
(P)->base.type = GIT_ITERATOR_TYPE_ ## NAME_UC; \
|
||||||
(P)->base.cb = &(P)->cb; \
|
(P)->base.cb = &(P)->cb; \
|
||||||
ITERATOR_SET_CB(P,NAME_LC); \
|
ITERATOR_SET_CB(P,NAME_LC); \
|
||||||
(P)->base.start = start ? git__strdup(start) : NULL; \
|
(P)->base.start = start ? git__strdup(start) : NULL; \
|
||||||
(P)->base.end = end ? git__strdup(end) : NULL; \
|
(P)->base.end = end ? git__strdup(end) : NULL; \
|
||||||
(P)->base.ignore_case = false; \
|
|
||||||
if ((start && !(P)->base.start) || (end && !(P)->base.end)) { \
|
if ((start && !(P)->base.start) || (end && !(P)->base.end)) { \
|
||||||
git__free(P); return -1; } \
|
git__free(P); return -1; } \
|
||||||
|
(P)->base.prefixcomp = git__prefixcmp; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static int iterator__reset_range(
|
static int iterator__reset_range(
|
||||||
@ -54,6 +54,34 @@ static int iterator__reset_range(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int iterator_update_ignore_case(
|
||||||
|
git_iterator *iter,
|
||||||
|
git_iterator_flag_t flags)
|
||||||
|
{
|
||||||
|
int error = 0, ignore_case = -1;
|
||||||
|
|
||||||
|
if ((flags & GIT_ITERATOR_IGNORE_CASE) != 0)
|
||||||
|
ignore_case = true;
|
||||||
|
else if ((flags & GIT_ITERATOR_DONT_IGNORE_CASE) != 0)
|
||||||
|
ignore_case = false;
|
||||||
|
else {
|
||||||
|
git_index *index;
|
||||||
|
|
||||||
|
if (!(error = git_repository_index__weakptr(&index, iter->repo)))
|
||||||
|
ignore_case = (index->ignore_case != false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignore_case > 0)
|
||||||
|
iter->flags = (iter->flags | GIT_ITERATOR_IGNORE_CASE);
|
||||||
|
else if (ignore_case == 0)
|
||||||
|
iter->flags = (iter->flags & ~GIT_ITERATOR_IGNORE_CASE);
|
||||||
|
|
||||||
|
iter->prefixcomp = ((iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0) ?
|
||||||
|
git__prefixcmp_icase : git__prefixcmp;
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
static int empty_iterator__no_item(
|
static int empty_iterator__no_item(
|
||||||
git_iterator *iter, const git_index_entry **entry)
|
git_iterator *iter, const git_index_entry **entry)
|
||||||
{
|
{
|
||||||
@ -91,13 +119,14 @@ typedef struct {
|
|||||||
git_iterator_callbacks cb;
|
git_iterator_callbacks cb;
|
||||||
} empty_iterator;
|
} empty_iterator;
|
||||||
|
|
||||||
int git_iterator_for_nothing(git_iterator **iter)
|
int git_iterator_for_nothing(git_iterator **iter, git_iterator_flag_t flags)
|
||||||
{
|
{
|
||||||
empty_iterator *i = git__calloc(1, sizeof(empty_iterator));
|
empty_iterator *i = git__calloc(1, sizeof(empty_iterator));
|
||||||
GITERR_CHECK_ALLOC(i);
|
GITERR_CHECK_ALLOC(i);
|
||||||
|
|
||||||
i->base.type = GIT_ITERATOR_EMPTY;
|
i->base.type = GIT_ITERATOR_TYPE_EMPTY;
|
||||||
i->base.cb = &i->cb;
|
i->base.cb = &i->cb;
|
||||||
|
i->base.flags = flags;
|
||||||
i->cb.current = empty_iterator__no_item;
|
i->cb.current = empty_iterator__no_item;
|
||||||
i->cb.at_end = empty_iterator__at_end;
|
i->cb.at_end = empty_iterator__at_end;
|
||||||
i->cb.advance = empty_iterator__no_item;
|
i->cb.advance = empty_iterator__no_item;
|
||||||
@ -116,7 +145,10 @@ struct tree_iterator_frame {
|
|||||||
tree_iterator_frame *next, *prev;
|
tree_iterator_frame *next, *prev;
|
||||||
git_tree *tree;
|
git_tree *tree;
|
||||||
char *start;
|
char *start;
|
||||||
|
size_t startlen;
|
||||||
size_t index;
|
size_t index;
|
||||||
|
void **icase_map;
|
||||||
|
void *icase_data[GIT_FLEX_ARRAY];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -130,7 +162,13 @@ typedef struct {
|
|||||||
|
|
||||||
GIT_INLINE(const git_tree_entry *)tree_iterator__tree_entry(tree_iterator *ti)
|
GIT_INLINE(const git_tree_entry *)tree_iterator__tree_entry(tree_iterator *ti)
|
||||||
{
|
{
|
||||||
return git_tree_entry_byindex(ti->stack->tree, ti->stack->index);
|
tree_iterator_frame *tf = ti->stack;
|
||||||
|
|
||||||
|
if (tf->index >= git_tree_entrycount(tf->tree))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return git_tree_entry_byindex(
|
||||||
|
tf->tree, tf->icase_map ? (size_t)tf->icase_map[tf->index] : tf->index);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *tree_iterator__current_filename(
|
static char *tree_iterator__current_filename(
|
||||||
@ -149,7 +187,10 @@ static void tree_iterator__free_frame(tree_iterator_frame *tf)
|
|||||||
{
|
{
|
||||||
if (!tf)
|
if (!tf)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
git_tree_free(tf->tree);
|
git_tree_free(tf->tree);
|
||||||
|
tf->tree = NULL;
|
||||||
|
|
||||||
git__free(tf);
|
git__free(tf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +236,7 @@ static int tree_iterator__current(
|
|||||||
if (ti->entry.path == NULL)
|
if (ti->entry.path == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (ti->base.end && git__prefixcmp(ti->entry.path, ti->base.end) > 0)
|
if (ti->base.end && ti->base.prefixcomp(ti->entry.path, ti->base.end) > 0)
|
||||||
return tree_iterator__to_end(ti);
|
return tree_iterator__to_end(ti);
|
||||||
|
|
||||||
if (entry)
|
if (entry)
|
||||||
@ -209,10 +250,50 @@ static int tree_iterator__at_end(git_iterator *self)
|
|||||||
return (tree_iterator__tree_entry((tree_iterator *)self) == NULL);
|
return (tree_iterator__tree_entry((tree_iterator *)self) == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static tree_iterator_frame *tree_iterator__alloc_frame(
|
static int tree_iterator__icase_map_cmp(const void *a, const void *b, void *data)
|
||||||
git_tree *tree, char *start)
|
|
||||||
{
|
{
|
||||||
tree_iterator_frame *tf = git__calloc(1, sizeof(tree_iterator_frame));
|
git_tree *tree = data;
|
||||||
|
const git_tree_entry *te1 = git_tree_entry_byindex(tree, (size_t)a);
|
||||||
|
const git_tree_entry *te2 = git_tree_entry_byindex(tree, (size_t)b);
|
||||||
|
return te1 ? (te2 ? git_tree_entry_icmp(te1, te2) : 1) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tree_iterator__frame_start_icmp(const void *key, const void *element)
|
||||||
|
{
|
||||||
|
const tree_iterator_frame *tf = (const tree_iterator_frame *)key;
|
||||||
|
const git_tree_entry *te = git_tree_entry_byindex(tf->tree, (size_t)element);
|
||||||
|
|
||||||
|
return memcmp(tf->start, te->filename, min(tf->startlen, te->filename_len));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tree_iterator__frame_seek_start(tree_iterator_frame *tf)
|
||||||
|
{
|
||||||
|
if (!tf->start)
|
||||||
|
tf->index = 0;
|
||||||
|
else if (!tf->icase_map)
|
||||||
|
tf->index = git_tree__prefix_position(tf->tree, tf->start);
|
||||||
|
else {
|
||||||
|
if (!git__bsearch(
|
||||||
|
tf->icase_map, git_tree_entrycount(tf->tree),
|
||||||
|
tf, tree_iterator__frame_start_icmp, &tf->index))
|
||||||
|
{
|
||||||
|
while (tf->index > 0) {
|
||||||
|
/* move back while previous entry is still prefixed */
|
||||||
|
if (tree_iterator__frame_start_icmp(
|
||||||
|
tf, (const void *)(tf->index - 1)))
|
||||||
|
break;
|
||||||
|
tf->index--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree_iterator_frame *tree_iterator__alloc_frame(
|
||||||
|
tree_iterator *ti, git_tree *tree, char *start)
|
||||||
|
{
|
||||||
|
size_t i, max_i = git_tree_entrycount(tree);
|
||||||
|
tree_iterator_frame *tf =
|
||||||
|
git__calloc(1, sizeof(tree_iterator_frame) + max_i * sizeof(void *));
|
||||||
if (!tf)
|
if (!tf)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -220,9 +301,24 @@ static tree_iterator_frame *tree_iterator__alloc_frame(
|
|||||||
|
|
||||||
if (start && *start) {
|
if (start && *start) {
|
||||||
tf->start = start;
|
tf->start = start;
|
||||||
tf->index = git_tree__prefix_position(tree, start);
|
tf->startlen = strlen(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!max_i)
|
||||||
|
return tf;
|
||||||
|
|
||||||
|
if ((ti->base.flags & GIT_ITERATOR_IGNORE_CASE) != 0) {
|
||||||
|
tf->icase_map = tf->icase_data;
|
||||||
|
|
||||||
|
for (i = 0; i < max_i; ++i)
|
||||||
|
tf->icase_map[i] = (void *)i;
|
||||||
|
|
||||||
|
git__tsort_r(
|
||||||
|
tf->icase_map, max_i, tree_iterator__icase_map_cmp, tf->tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
tree_iterator__frame_seek_start(tf);
|
||||||
|
|
||||||
return tf;
|
return tf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +336,7 @@ static int tree_iterator__expand_tree(tree_iterator *ti)
|
|||||||
|
|
||||||
/* check that we have not passed the range end */
|
/* check that we have not passed the range end */
|
||||||
if (ti->base.end != NULL &&
|
if (ti->base.end != NULL &&
|
||||||
git__prefixcmp(ti->path.ptr, ti->base.end) > 0)
|
ti->base.prefixcomp(ti->path.ptr, ti->base.end) > 0)
|
||||||
return tree_iterator__to_end(ti);
|
return tree_iterator__to_end(ti);
|
||||||
|
|
||||||
if ((error = git_tree_lookup(&subtree, ti->base.repo, &te->oid)) < 0)
|
if ((error = git_tree_lookup(&subtree, ti->base.repo, &te->oid)) < 0)
|
||||||
@ -250,14 +346,13 @@ static int tree_iterator__expand_tree(tree_iterator *ti)
|
|||||||
|
|
||||||
/* apply range start to new frame if relevant */
|
/* apply range start to new frame if relevant */
|
||||||
if (ti->stack->start &&
|
if (ti->stack->start &&
|
||||||
git__prefixcmp(ti->stack->start, te->filename) == 0)
|
ti->base.prefixcomp(ti->stack->start, te->filename) == 0)
|
||||||
{
|
{
|
||||||
size_t namelen = strlen(te->filename);
|
if (ti->stack->start[te->filename_len] == '/')
|
||||||
if (ti->stack->start[namelen] == '/')
|
relpath = ti->stack->start + te->filename_len + 1;
|
||||||
relpath = ti->stack->start + namelen + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((tf = tree_iterator__alloc_frame(subtree, relpath)) == NULL)
|
if ((tf = tree_iterator__alloc_frame(ti, subtree, relpath)) == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
tf->next = ti->stack;
|
tf->next = ti->stack;
|
||||||
@ -286,8 +381,9 @@ static int tree_iterator__advance(
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
te = git_tree_entry_byindex(ti->stack->tree, ++ti->stack->index);
|
++ti->stack->index;
|
||||||
if (te != NULL)
|
|
||||||
|
if ((te = tree_iterator__tree_entry(ti)) != NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!tree_iterator__pop_frame(ti))
|
if (!tree_iterator__pop_frame(ti))
|
||||||
@ -337,8 +433,8 @@ static int tree_iterator__reset(
|
|||||||
if (iterator__reset_range(self, start, end) < 0)
|
if (iterator__reset_range(self, start, end) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ti->stack->index =
|
/* reset start position */
|
||||||
git_tree__prefix_position(ti->stack->tree, ti->base.start);
|
tree_iterator__frame_seek_start(ti->stack);
|
||||||
|
|
||||||
git_buf_clear(&ti->path);
|
git_buf_clear(&ti->path);
|
||||||
ti->path_has_filename = false;
|
ti->path_has_filename = false;
|
||||||
@ -349,6 +445,7 @@ static int tree_iterator__reset(
|
|||||||
int git_iterator_for_tree_range(
|
int git_iterator_for_tree_range(
|
||||||
git_iterator **iter,
|
git_iterator **iter,
|
||||||
git_tree *tree,
|
git_tree *tree,
|
||||||
|
git_iterator_flag_t flags,
|
||||||
const char *start,
|
const char *start,
|
||||||
const char *end)
|
const char *end)
|
||||||
{
|
{
|
||||||
@ -356,7 +453,7 @@ int git_iterator_for_tree_range(
|
|||||||
tree_iterator *ti;
|
tree_iterator *ti;
|
||||||
|
|
||||||
if (tree == NULL)
|
if (tree == NULL)
|
||||||
return git_iterator_for_nothing(iter);
|
return git_iterator_for_nothing(iter, flags);
|
||||||
|
|
||||||
if ((error = git_tree__dup(&tree, tree)) < 0)
|
if ((error = git_tree__dup(&tree, tree)) < 0)
|
||||||
return error;
|
return error;
|
||||||
@ -364,13 +461,20 @@ int git_iterator_for_tree_range(
|
|||||||
ITERATOR_BASE_INIT(ti, tree, TREE);
|
ITERATOR_BASE_INIT(ti, tree, TREE);
|
||||||
|
|
||||||
ti->base.repo = git_tree_owner(tree);
|
ti->base.repo = git_tree_owner(tree);
|
||||||
ti->stack = ti->tail = tree_iterator__alloc_frame(tree, ti->base.start);
|
|
||||||
|
if ((error = iterator_update_ignore_case((git_iterator *)ti, flags)) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
ti->stack = ti->tail = tree_iterator__alloc_frame(ti, tree, ti->base.start);
|
||||||
|
|
||||||
if ((error = tree_iterator__expand_tree(ti)) < 0)
|
if ((error = tree_iterator__expand_tree(ti)) < 0)
|
||||||
git_iterator_free((git_iterator *)ti);
|
goto fail;
|
||||||
else
|
|
||||||
*iter = (git_iterator *)ti;
|
|
||||||
|
|
||||||
|
*iter = (git_iterator *)ti;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
git_iterator_free((git_iterator *)ti);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,7 +515,7 @@ static void index_iterator__skip_conflicts(
|
|||||||
|
|
||||||
if (ie == NULL ||
|
if (ie == NULL ||
|
||||||
(ii->base.end != NULL &&
|
(ii->base.end != NULL &&
|
||||||
ITERATOR_PREFIXCMP(ii->base, ie->path, ii->base.end) > 0)) {
|
ii->base.prefixcomp(ie->path, ii->base.end) > 0)) {
|
||||||
ii->current = entrycount;
|
ii->current = entrycount;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -466,15 +570,21 @@ static void index_iterator__free(git_iterator *self)
|
|||||||
int git_iterator_for_index_range(
|
int git_iterator_for_index_range(
|
||||||
git_iterator **iter,
|
git_iterator **iter,
|
||||||
git_index *index,
|
git_index *index,
|
||||||
|
git_iterator_flag_t flags,
|
||||||
const char *start,
|
const char *start,
|
||||||
const char *end)
|
const char *end)
|
||||||
{
|
{
|
||||||
index_iterator *ii;
|
index_iterator *ii;
|
||||||
|
|
||||||
|
GIT_UNUSED(flags);
|
||||||
|
|
||||||
ITERATOR_BASE_INIT(ii, index, INDEX);
|
ITERATOR_BASE_INIT(ii, index, INDEX);
|
||||||
|
|
||||||
ii->base.repo = git_index_owner(index);
|
ii->base.repo = git_index_owner(index);
|
||||||
ii->base.ignore_case = index->ignore_case;
|
if (index->ignore_case) {
|
||||||
|
ii->base.flags |= GIT_ITERATOR_IGNORE_CASE;
|
||||||
|
ii->base.prefixcomp = git__prefixcmp_icase;
|
||||||
|
}
|
||||||
ii->index = index;
|
ii->index = index;
|
||||||
GIT_REFCOUNT_INC(index);
|
GIT_REFCOUNT_INC(index);
|
||||||
|
|
||||||
@ -485,20 +595,6 @@ int git_iterator_for_index_range(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_iterator_for_repo_index_range(
|
|
||||||
git_iterator **iter,
|
|
||||||
git_repository *repo,
|
|
||||||
const char *start,
|
|
||||||
const char *end)
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
git_index *index;
|
|
||||||
|
|
||||||
if ((error = git_repository_index__weakptr(&index, repo)) < 0)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
return git_iterator_for_index_range(iter, index, start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct workdir_iterator_frame workdir_iterator_frame;
|
typedef struct workdir_iterator_frame workdir_iterator_frame;
|
||||||
struct workdir_iterator_frame {
|
struct workdir_iterator_frame {
|
||||||
@ -544,7 +640,8 @@ static workdir_iterator_frame *workdir_iterator__alloc_frame(
|
|||||||
workdir_iterator *wi)
|
workdir_iterator *wi)
|
||||||
{
|
{
|
||||||
workdir_iterator_frame *wf = git__calloc(1, sizeof(workdir_iterator_frame));
|
workdir_iterator_frame *wf = git__calloc(1, sizeof(workdir_iterator_frame));
|
||||||
git_vector_cmp entry_compare = CASESELECT(wi->base.ignore_case,
|
git_vector_cmp entry_compare = CASESELECT(
|
||||||
|
(wi->base.flags & GIT_ITERATOR_IGNORE_CASE) != 0,
|
||||||
git_path_with_stat_cmp_icase, git_path_with_stat_cmp);
|
git_path_with_stat_cmp_icase, git_path_with_stat_cmp);
|
||||||
|
|
||||||
if (wf == NULL)
|
if (wf == NULL)
|
||||||
@ -606,7 +703,8 @@ static int workdir_iterator__expand_dir(workdir_iterator *wi)
|
|||||||
GITERR_CHECK_ALLOC(wf);
|
GITERR_CHECK_ALLOC(wf);
|
||||||
|
|
||||||
error = git_path_dirload_with_stat(
|
error = git_path_dirload_with_stat(
|
||||||
wi->path.ptr, wi->root_len, wi->base.ignore_case,
|
wi->path.ptr, wi->root_len,
|
||||||
|
(wi->base.flags & GIT_ITERATOR_IGNORE_CASE) != 0,
|
||||||
wi->base.start, wi->base.end, &wf->entries);
|
wi->base.start, wi->base.end, &wf->entries);
|
||||||
|
|
||||||
if (error < 0 || wf->entries.length == 0) {
|
if (error < 0 || wf->entries.length == 0) {
|
||||||
@ -744,8 +842,8 @@ static int workdir_iterator__update_entry(workdir_iterator *wi)
|
|||||||
if (git_buf_put(&wi->path, ps->path, ps->path_len) < 0)
|
if (git_buf_put(&wi->path, ps->path, ps->path_len) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (wi->base.end && ITERATOR_PREFIXCMP(
|
if (wi->base.end &&
|
||||||
wi->base, wi->path.ptr + wi->root_len, wi->base.end) > 0)
|
wi->base.prefixcomp(wi->path.ptr + wi->root_len, wi->base.end) > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
wi->entry.path = ps->path;
|
wi->entry.path = ps->path;
|
||||||
@ -789,12 +887,12 @@ static int workdir_iterator__update_entry(workdir_iterator *wi)
|
|||||||
int git_iterator_for_workdir_range(
|
int git_iterator_for_workdir_range(
|
||||||
git_iterator **iter,
|
git_iterator **iter,
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
|
git_iterator_flag_t flags,
|
||||||
const char *start,
|
const char *start,
|
||||||
const char *end)
|
const char *end)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
workdir_iterator *wi;
|
workdir_iterator *wi;
|
||||||
git_index *index;
|
|
||||||
|
|
||||||
assert(iter && repo);
|
assert(iter && repo);
|
||||||
|
|
||||||
@ -805,13 +903,8 @@ int git_iterator_for_workdir_range(
|
|||||||
ITERATOR_BASE_INIT(wi, workdir, WORKDIR);
|
ITERATOR_BASE_INIT(wi, workdir, WORKDIR);
|
||||||
wi->base.repo = repo;
|
wi->base.repo = repo;
|
||||||
|
|
||||||
if ((error = git_repository_index__weakptr(&index, repo)) < 0) {
|
if ((error = iterator_update_ignore_case((git_iterator *)wi, flags)) < 0)
|
||||||
git_iterator_free((git_iterator *)wi);
|
goto fail;
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Match ignore_case flag for iterator to that of the index */
|
|
||||||
wi->base.ignore_case = index->ignore_case;
|
|
||||||
|
|
||||||
if (git_buf_sets(&wi->path, git_repository_workdir(repo)) < 0 ||
|
if (git_buf_sets(&wi->path, git_repository_workdir(repo)) < 0 ||
|
||||||
git_path_to_dir(&wi->path) < 0 ||
|
git_path_to_dir(&wi->path) < 0 ||
|
||||||
@ -822,23 +915,24 @@ int git_iterator_for_workdir_range(
|
|||||||
}
|
}
|
||||||
|
|
||||||
wi->root_len = wi->path.size;
|
wi->root_len = wi->path.size;
|
||||||
wi->entrycmp = wi->base.ignore_case ?
|
wi->entrycmp = (wi->base.flags & GIT_ITERATOR_IGNORE_CASE) != 0 ?
|
||||||
workdir_iterator__entry_cmp_icase : workdir_iterator__entry_cmp_case;
|
workdir_iterator__entry_cmp_icase : workdir_iterator__entry_cmp_case;
|
||||||
|
|
||||||
if ((error = workdir_iterator__expand_dir(wi)) < 0) {
|
if ((error = workdir_iterator__expand_dir(wi)) < 0) {
|
||||||
if (error == GIT_ENOTFOUND)
|
if (error != GIT_ENOTFOUND)
|
||||||
error = 0;
|
goto fail;
|
||||||
else {
|
giterr_clear();
|
||||||
git_iterator_free((git_iterator *)wi);
|
|
||||||
wi = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*iter = (git_iterator *)wi;
|
*iter = (git_iterator *)wi;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
git_iterator_free((git_iterator *)wi);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* replacement callbacks */
|
/* replacement callbacks */
|
||||||
git_iterator_callbacks cb;
|
git_iterator_callbacks cb;
|
||||||
@ -913,12 +1007,12 @@ void git_iterator_spoolandsort_pop(git_iterator *self)
|
|||||||
{
|
{
|
||||||
spoolandsort_callbacks *scb = (spoolandsort_callbacks *)self->cb;
|
spoolandsort_callbacks *scb = (spoolandsort_callbacks *)self->cb;
|
||||||
|
|
||||||
if (self->type != GIT_ITERATOR_SPOOLANDSORT)
|
if (self->type != GIT_ITERATOR_TYPE_SPOOLANDSORT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
self->cb = scb->orig;
|
self->cb = scb->orig;
|
||||||
self->type = scb->orig_type;
|
self->type = scb->orig_type;
|
||||||
self->ignore_case = !self->ignore_case;
|
self->flags ^= GIT_ITERATOR_IGNORE_CASE;
|
||||||
|
|
||||||
spoolandsort_iterator__free_callbacks(scb);
|
spoolandsort_iterator__free_callbacks(scb);
|
||||||
}
|
}
|
||||||
@ -935,9 +1029,14 @@ int git_iterator_spoolandsort_push(git_iterator *iter, bool ignore_case)
|
|||||||
spoolandsort_callbacks *scb;
|
spoolandsort_callbacks *scb;
|
||||||
int (*entrycomp)(const void *a, const void *b);
|
int (*entrycomp)(const void *a, const void *b);
|
||||||
|
|
||||||
if (iter->ignore_case == ignore_case)
|
if (((iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0) == (ignore_case != 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (iter->type == GIT_ITERATOR_TYPE_EMPTY) {
|
||||||
|
iter->flags = (iter->flags ^ GIT_ITERATOR_IGNORE_CASE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
scb = git__calloc(1, sizeof(spoolandsort_callbacks));
|
scb = git__calloc(1, sizeof(spoolandsort_callbacks));
|
||||||
GITERR_CHECK_ALLOC(scb);
|
GITERR_CHECK_ALLOC(scb);
|
||||||
|
|
||||||
@ -978,8 +1077,8 @@ int git_iterator_spoolandsort_push(git_iterator *iter, bool ignore_case)
|
|||||||
git_vector_sort(&scb->entries);
|
git_vector_sort(&scb->entries);
|
||||||
|
|
||||||
iter->cb = (git_iterator_callbacks *)scb;
|
iter->cb = (git_iterator_callbacks *)scb;
|
||||||
iter->type = GIT_ITERATOR_SPOOLANDSORT;
|
iter->type = GIT_ITERATOR_TYPE_SPOOLANDSORT;
|
||||||
iter->ignore_case = !iter->ignore_case;
|
iter->flags ^= GIT_ITERATOR_IGNORE_CASE;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -988,13 +1087,29 @@ fail:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void git_iterator_free(git_iterator *iter)
|
||||||
|
{
|
||||||
|
if (iter == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
iter->cb->free(iter);
|
||||||
|
|
||||||
|
git__free(iter->start);
|
||||||
|
git__free(iter->end);
|
||||||
|
|
||||||
|
memset(iter, 0, sizeof(*iter));
|
||||||
|
|
||||||
|
git__free(iter);
|
||||||
|
}
|
||||||
|
|
||||||
git_index *git_iterator_index_get_index(git_iterator *iter)
|
git_index *git_iterator_index_get_index(git_iterator *iter)
|
||||||
{
|
{
|
||||||
if (iter->type == GIT_ITERATOR_INDEX)
|
if (iter->type == GIT_ITERATOR_TYPE_INDEX)
|
||||||
return ((index_iterator *)iter)->index;
|
return ((index_iterator *)iter)->index;
|
||||||
|
|
||||||
if (iter->type == GIT_ITERATOR_SPOOLANDSORT &&
|
if (iter->type == GIT_ITERATOR_TYPE_SPOOLANDSORT &&
|
||||||
((spoolandsort_callbacks *)iter->cb)->orig_type == GIT_ITERATOR_INDEX)
|
((spoolandsort_callbacks *)iter->cb)->orig_type == GIT_ITERATOR_TYPE_INDEX)
|
||||||
return ((index_iterator *)iter)->index;
|
return ((index_iterator *)iter)->index;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1002,7 +1117,7 @@ git_index *git_iterator_index_get_index(git_iterator *iter)
|
|||||||
|
|
||||||
git_iterator_type_t git_iterator_inner_type(git_iterator *iter)
|
git_iterator_type_t git_iterator_inner_type(git_iterator *iter)
|
||||||
{
|
{
|
||||||
if (iter->type == GIT_ITERATOR_SPOOLANDSORT)
|
if (iter->type == GIT_ITERATOR_TYPE_SPOOLANDSORT)
|
||||||
return ((spoolandsort_callbacks *)iter->cb)->orig_type;
|
return ((spoolandsort_callbacks *)iter->cb)->orig_type;
|
||||||
|
|
||||||
return iter->type;
|
return iter->type;
|
||||||
@ -1011,7 +1126,7 @@ git_iterator_type_t git_iterator_inner_type(git_iterator *iter)
|
|||||||
int git_iterator_current_tree_entry(
|
int git_iterator_current_tree_entry(
|
||||||
git_iterator *iter, const git_tree_entry **tree_entry)
|
git_iterator *iter, const git_tree_entry **tree_entry)
|
||||||
{
|
{
|
||||||
*tree_entry = (iter->type != GIT_ITERATOR_TREE) ? NULL :
|
*tree_entry = (iter->type != GIT_ITERATOR_TYPE_TREE) ? NULL :
|
||||||
tree_iterator__tree_entry((tree_iterator *)iter);
|
tree_iterator__tree_entry((tree_iterator *)iter);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1024,10 +1139,14 @@ int git_iterator_current_parent_tree(
|
|||||||
tree_iterator *ti = (tree_iterator *)iter;
|
tree_iterator *ti = (tree_iterator *)iter;
|
||||||
tree_iterator_frame *tf;
|
tree_iterator_frame *tf;
|
||||||
const char *scan = parent_path;
|
const char *scan = parent_path;
|
||||||
|
int (*strncomp)(const char *a, const char *b, size_t sz);
|
||||||
|
|
||||||
if (iter->type != GIT_ITERATOR_TREE || ti->stack == NULL)
|
if (iter->type != GIT_ITERATOR_TYPE_TREE || ti->stack == NULL)
|
||||||
goto notfound;
|
goto notfound;
|
||||||
|
|
||||||
|
strncomp = ((iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0) ?
|
||||||
|
git__strncasecmp : git__strncmp;
|
||||||
|
|
||||||
for (tf = ti->tail; tf != NULL; tf = tf->prev) {
|
for (tf = ti->tail; tf != NULL; tf = tf->prev) {
|
||||||
const git_tree_entry *te;
|
const git_tree_entry *te;
|
||||||
|
|
||||||
@ -1036,9 +1155,10 @@ int git_iterator_current_parent_tree(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
te = git_tree_entry_byindex(tf->tree, tf->index);
|
te = git_tree_entry_byindex(tf->tree,
|
||||||
|
tf->icase_map ? (size_t)tf->icase_map[tf->index] : tf->index);
|
||||||
|
|
||||||
if (strncmp(scan, te->filename, te->filename_len) != 0)
|
if (strncomp(scan, te->filename, te->filename_len) != 0)
|
||||||
goto notfound;
|
goto notfound;
|
||||||
|
|
||||||
scan += te->filename_len;
|
scan += te->filename_len;
|
||||||
@ -1059,7 +1179,7 @@ int git_iterator_current_is_ignored(git_iterator *iter)
|
|||||||
{
|
{
|
||||||
workdir_iterator *wi = (workdir_iterator *)iter;
|
workdir_iterator *wi = (workdir_iterator *)iter;
|
||||||
|
|
||||||
if (iter->type != GIT_ITERATOR_WORKDIR)
|
if (iter->type != GIT_ITERATOR_TYPE_WORKDIR)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (wi->is_ignored != -1)
|
if (wi->is_ignored != -1)
|
||||||
@ -1076,7 +1196,7 @@ int git_iterator_advance_into_directory(
|
|||||||
{
|
{
|
||||||
workdir_iterator *wi = (workdir_iterator *)iter;
|
workdir_iterator *wi = (workdir_iterator *)iter;
|
||||||
|
|
||||||
if (iter->type == GIT_ITERATOR_WORKDIR &&
|
if (iter->type == GIT_ITERATOR_TYPE_WORKDIR &&
|
||||||
wi->entry.path &&
|
wi->entry.path &&
|
||||||
(wi->entry.mode == GIT_FILEMODE_TREE ||
|
(wi->entry.mode == GIT_FILEMODE_TREE ||
|
||||||
wi->entry.mode == GIT_FILEMODE_COMMIT))
|
wi->entry.mode == GIT_FILEMODE_COMMIT))
|
||||||
@ -1089,8 +1209,7 @@ int git_iterator_advance_into_directory(
|
|||||||
return entry ? git_iterator_current(iter, entry) : 0;
|
return entry ? git_iterator_current(iter, entry) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_iterator_cmp(
|
int git_iterator_cmp(git_iterator *iter, const char *path_prefix)
|
||||||
git_iterator *iter, const char *path_prefix)
|
|
||||||
{
|
{
|
||||||
const git_index_entry *entry;
|
const git_index_entry *entry;
|
||||||
|
|
||||||
@ -1103,14 +1222,14 @@ int git_iterator_cmp(
|
|||||||
if (!path_prefix)
|
if (!path_prefix)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return ITERATOR_PREFIXCMP(*iter, entry->path, path_prefix);
|
return iter->prefixcomp(entry->path, path_prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_iterator_current_workdir_path(git_iterator *iter, git_buf **path)
|
int git_iterator_current_workdir_path(git_iterator *iter, git_buf **path)
|
||||||
{
|
{
|
||||||
workdir_iterator *wi = (workdir_iterator *)iter;
|
workdir_iterator *wi = (workdir_iterator *)iter;
|
||||||
|
|
||||||
if (iter->type != GIT_ITERATOR_WORKDIR || !wi->entry.path)
|
if (iter->type != GIT_ITERATOR_TYPE_WORKDIR || !wi->entry.path)
|
||||||
*path = NULL;
|
*path = NULL;
|
||||||
else
|
else
|
||||||
*path = &wi->path;
|
*path = &wi->path;
|
||||||
|
105
src/iterator.h
105
src/iterator.h
@ -12,20 +12,26 @@
|
|||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
#define ITERATOR_PREFIXCMP(ITER, STR, PREFIX) (((ITER).ignore_case) ? \
|
#define ITERATOR_PREFIXCMP(ITER, STR, PREFIX) \
|
||||||
|
(((ITER).flags & GIT_ITERATOR_IGNORE_CASE) != 0 ? \
|
||||||
git__prefixcmp_icase((STR), (PREFIX)) : \
|
git__prefixcmp_icase((STR), (PREFIX)) : \
|
||||||
git__prefixcmp((STR), (PREFIX)))
|
git__prefixcmp((STR), (PREFIX)))
|
||||||
|
|
||||||
typedef struct git_iterator git_iterator;
|
typedef struct git_iterator git_iterator;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GIT_ITERATOR_EMPTY = 0,
|
GIT_ITERATOR_TYPE_EMPTY = 0,
|
||||||
GIT_ITERATOR_TREE = 1,
|
GIT_ITERATOR_TYPE_TREE = 1,
|
||||||
GIT_ITERATOR_INDEX = 2,
|
GIT_ITERATOR_TYPE_INDEX = 2,
|
||||||
GIT_ITERATOR_WORKDIR = 3,
|
GIT_ITERATOR_TYPE_WORKDIR = 3,
|
||||||
GIT_ITERATOR_SPOOLANDSORT = 4
|
GIT_ITERATOR_TYPE_SPOOLANDSORT = 4
|
||||||
} git_iterator_type_t;
|
} git_iterator_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GIT_ITERATOR_IGNORE_CASE = (1 << 0), /* ignore_case */
|
||||||
|
GIT_ITERATOR_DONT_IGNORE_CASE = (1 << 1), /* force ignore_case off */
|
||||||
|
} git_iterator_flag_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int (*current)(git_iterator *, const git_index_entry **);
|
int (*current)(git_iterator *, const git_index_entry **);
|
||||||
int (*at_end)(git_iterator *);
|
int (*at_end)(git_iterator *);
|
||||||
@ -41,50 +47,60 @@ struct git_iterator {
|
|||||||
git_repository *repo;
|
git_repository *repo;
|
||||||
char *start;
|
char *start;
|
||||||
char *end;
|
char *end;
|
||||||
bool ignore_case;
|
int (*prefixcomp)(const char *str, const char *prefix);
|
||||||
|
unsigned int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int git_iterator_for_nothing(git_iterator **iter);
|
extern int git_iterator_for_nothing(
|
||||||
|
git_iterator **out, git_iterator_flag_t flags);
|
||||||
|
|
||||||
|
/* tree iterators will match the ignore_case value from the index of the
|
||||||
|
* repository, unless you override with a non-zero flag value
|
||||||
|
*/
|
||||||
extern int git_iterator_for_tree_range(
|
extern int git_iterator_for_tree_range(
|
||||||
git_iterator **iter, git_tree *tree,
|
git_iterator **out,
|
||||||
const char *start, const char *end);
|
git_tree *tree,
|
||||||
|
git_iterator_flag_t flags,
|
||||||
|
const char *start,
|
||||||
|
const char *end);
|
||||||
|
|
||||||
GIT_INLINE(int) git_iterator_for_tree(
|
GIT_INLINE(int) git_iterator_for_tree(git_iterator **out, git_tree *tree)
|
||||||
git_iterator **iter, git_tree *tree)
|
|
||||||
{
|
{
|
||||||
return git_iterator_for_tree_range(iter, tree, NULL, NULL);
|
return git_iterator_for_tree_range(out, tree, 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* index iterators will take the ignore_case value from the index; the
|
||||||
|
* ignore_case flags are not used
|
||||||
|
*/
|
||||||
extern int git_iterator_for_index_range(
|
extern int git_iterator_for_index_range(
|
||||||
git_iterator **iter, git_index *index, const char *start, const char *end);
|
git_iterator **out,
|
||||||
|
git_index *index,
|
||||||
|
git_iterator_flag_t flags,
|
||||||
|
const char *start,
|
||||||
|
const char *end);
|
||||||
|
|
||||||
GIT_INLINE(int) git_iterator_for_index(
|
GIT_INLINE(int) git_iterator_for_index(git_iterator **out, git_index *index)
|
||||||
git_iterator **iter, git_index *index)
|
|
||||||
{
|
{
|
||||||
return git_iterator_for_index_range(iter, index, NULL, NULL);
|
return git_iterator_for_index_range(out, index, 0, NULL, NULL);
|
||||||
}
|
|
||||||
|
|
||||||
extern int git_iterator_for_repo_index_range(
|
|
||||||
git_iterator **iter, git_repository *repo,
|
|
||||||
const char *start, const char *end);
|
|
||||||
|
|
||||||
GIT_INLINE(int) git_iterator_for_repo_index(
|
|
||||||
git_iterator **iter, git_repository *repo)
|
|
||||||
{
|
|
||||||
return git_iterator_for_repo_index_range(iter, repo, NULL, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* workdir iterators will match the ignore_case value from the index of the
|
||||||
|
* repository, unless you override with a non-zero flag value
|
||||||
|
*/
|
||||||
extern int git_iterator_for_workdir_range(
|
extern int git_iterator_for_workdir_range(
|
||||||
git_iterator **iter, git_repository *repo,
|
git_iterator **out,
|
||||||
const char *start, const char *end);
|
git_repository *repo,
|
||||||
|
git_iterator_flag_t flags,
|
||||||
|
const char *start,
|
||||||
|
const char *end);
|
||||||
|
|
||||||
GIT_INLINE(int) git_iterator_for_workdir(
|
GIT_INLINE(int) git_iterator_for_workdir(git_iterator **out, git_repository *repo)
|
||||||
git_iterator **iter, git_repository *repo)
|
|
||||||
{
|
{
|
||||||
return git_iterator_for_workdir_range(iter, repo, NULL, NULL);
|
return git_iterator_for_workdir_range(out, repo, 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void git_iterator_free(git_iterator *iter);
|
||||||
|
|
||||||
/* Spool all iterator values, resort with alternative ignore_case value
|
/* Spool all iterator values, resort with alternative ignore_case value
|
||||||
* and replace callbacks with spoolandsort alternates.
|
* and replace callbacks with spoolandsort alternates.
|
||||||
*/
|
*/
|
||||||
@ -130,21 +146,6 @@ GIT_INLINE(int) git_iterator_reset(
|
|||||||
return iter->cb->reset(iter, start, end);
|
return iter->cb->reset(iter, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
GIT_INLINE(void) git_iterator_free(git_iterator *iter)
|
|
||||||
{
|
|
||||||
if (iter == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
iter->cb->free(iter);
|
|
||||||
|
|
||||||
git__free(iter->start);
|
|
||||||
git__free(iter->end);
|
|
||||||
|
|
||||||
memset(iter, 0, sizeof(*iter));
|
|
||||||
|
|
||||||
git__free(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
GIT_INLINE(git_iterator_type_t) git_iterator_type(git_iterator *iter)
|
GIT_INLINE(git_iterator_type_t) git_iterator_type(git_iterator *iter)
|
||||||
{
|
{
|
||||||
return iter->type;
|
return iter->type;
|
||||||
@ -155,6 +156,16 @@ GIT_INLINE(git_repository *) git_iterator_owner(git_iterator *iter)
|
|||||||
return iter->repo;
|
return iter->repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GIT_INLINE(git_iterator_flag_t) git_iterator_flags(git_iterator *iter)
|
||||||
|
{
|
||||||
|
return iter->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
GIT_INLINE(bool) git_iterator_ignore_case(git_iterator *iter)
|
||||||
|
{
|
||||||
|
return ((iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
extern int git_iterator_current_tree_entry(
|
extern int git_iterator_current_tree_entry(
|
||||||
git_iterator *iter, const git_tree_entry **tree_entry);
|
git_iterator *iter, const git_tree_entry **tree_entry);
|
||||||
|
|
||||||
|
24
src/path.c
24
src/path.c
@ -701,6 +701,30 @@ int git_path_cmp(
|
|||||||
return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
|
return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_path_icmp(
|
||||||
|
const char *name1, size_t len1, int isdir1,
|
||||||
|
const char *name2, size_t len2, int isdir2)
|
||||||
|
{
|
||||||
|
unsigned char c1, c2;
|
||||||
|
size_t len = len1 < len2 ? len1 : len2;
|
||||||
|
int cmp;
|
||||||
|
|
||||||
|
cmp = strncasecmp(name1, name2, len);
|
||||||
|
if (cmp)
|
||||||
|
return cmp;
|
||||||
|
|
||||||
|
c1 = name1[len];
|
||||||
|
c2 = name2[len];
|
||||||
|
|
||||||
|
if (c1 == '\0' && isdir1)
|
||||||
|
c1 = '/';
|
||||||
|
|
||||||
|
if (c2 == '\0' && isdir2)
|
||||||
|
c2 = '/';
|
||||||
|
|
||||||
|
return (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
int git_path_direach(
|
int git_path_direach(
|
||||||
git_buf *path,
|
git_buf *path,
|
||||||
int (*fn)(void *, git_buf *),
|
int (*fn)(void *, git_buf *),
|
||||||
|
@ -261,12 +261,17 @@ extern int git_path_direach(
|
|||||||
void *state);
|
void *state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort function to order two paths.
|
* Sort function to order two paths
|
||||||
*/
|
*/
|
||||||
extern int git_path_cmp(
|
extern int git_path_cmp(
|
||||||
const char *name1, size_t len1, int isdir1,
|
const char *name1, size_t len1, int isdir1,
|
||||||
const char *name2, size_t len2, int isdir2);
|
const char *name2, size_t len2, int isdir2);
|
||||||
|
|
||||||
|
/** Path sort function that is case insensitive */
|
||||||
|
extern int git_path_icmp(
|
||||||
|
const char *name1, size_t len1, int isdir1,
|
||||||
|
const char *name2, size_t len2, int isdir2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke callback up path directory by directory until the ceiling is
|
* Invoke callback up path directory by directory until the ceiling is
|
||||||
* reached (inclusive of a final call at the root_path).
|
* reached (inclusive of a final call at the root_path).
|
||||||
|
22
src/status.c
22
src/status.c
@ -196,21 +196,24 @@ struct status_file_info {
|
|||||||
char *expected;
|
char *expected;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
|
int fnm_flags;
|
||||||
int ambiguous;
|
int ambiguous;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int get_one_status(const char *path, unsigned int status, void *data)
|
static int get_one_status(const char *path, unsigned int status, void *data)
|
||||||
{
|
{
|
||||||
struct status_file_info *sfi = data;
|
struct status_file_info *sfi = data;
|
||||||
|
int (*strcomp)(const char *a, const char *b);
|
||||||
|
|
||||||
sfi->count++;
|
sfi->count++;
|
||||||
sfi->status = status;
|
sfi->status = status;
|
||||||
|
|
||||||
|
strcomp = (sfi->fnm_flags & FNM_CASEFOLD) ? git__strcasecmp : git__strcmp;
|
||||||
|
|
||||||
if (sfi->count > 1 ||
|
if (sfi->count > 1 ||
|
||||||
(strcmp(sfi->expected, path) != 0 &&
|
(strcomp(sfi->expected, path) != 0 &&
|
||||||
p_fnmatch(sfi->expected, path, 0) != 0)) {
|
p_fnmatch(sfi->expected, path, sfi->fnm_flags) != 0))
|
||||||
giterr_set(GITERR_INVALID,
|
{
|
||||||
"Ambiguous path '%s' given to git_status_file", sfi->expected);
|
|
||||||
sfi->ambiguous = true;
|
sfi->ambiguous = true;
|
||||||
return GIT_EAMBIGUOUS;
|
return GIT_EAMBIGUOUS;
|
||||||
}
|
}
|
||||||
@ -226,11 +229,17 @@ int git_status_file(
|
|||||||
int error;
|
int error;
|
||||||
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
|
||||||
struct status_file_info sfi = {0};
|
struct status_file_info sfi = {0};
|
||||||
|
git_index *index;
|
||||||
|
|
||||||
assert(status_flags && repo && path);
|
assert(status_flags && repo && path);
|
||||||
|
|
||||||
|
if ((error = git_repository_index__weakptr(&index, repo)) < 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
if ((sfi.expected = git__strdup(path)) == NULL)
|
if ((sfi.expected = git__strdup(path)) == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
if (index->ignore_case)
|
||||||
|
sfi.fnm_flags = FNM_CASEFOLD;
|
||||||
|
|
||||||
opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
|
opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
|
||||||
opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED |
|
opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED |
|
||||||
@ -242,8 +251,11 @@ int git_status_file(
|
|||||||
|
|
||||||
error = git_status_foreach_ext(repo, &opts, get_one_status, &sfi);
|
error = git_status_foreach_ext(repo, &opts, get_one_status, &sfi);
|
||||||
|
|
||||||
if (error < 0 && sfi.ambiguous)
|
if (error < 0 && sfi.ambiguous) {
|
||||||
|
giterr_set(GITERR_INVALID,
|
||||||
|
"Ambiguous path '%s' given to git_status_file", sfi.expected);
|
||||||
error = GIT_EAMBIGUOUS;
|
error = GIT_EAMBIGUOUS;
|
||||||
|
}
|
||||||
|
|
||||||
if (!error && !sfi.count) {
|
if (!error && !sfi.count) {
|
||||||
git_buf full = GIT_BUF_INIT;
|
git_buf full = GIT_BUF_INIT;
|
||||||
|
@ -1130,10 +1130,12 @@ static int load_submodule_config_from_index(
|
|||||||
git_repository *repo, git_oid *gitmodules_oid)
|
git_repository *repo, git_oid *gitmodules_oid)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
git_index *index;
|
||||||
git_iterator *i;
|
git_iterator *i;
|
||||||
const git_index_entry *entry;
|
const git_index_entry *entry;
|
||||||
|
|
||||||
if ((error = git_iterator_for_repo_index(&i, repo)) < 0)
|
if ((error = git_repository_index__weakptr(&index, repo)) < 0 ||
|
||||||
|
(error = git_iterator_for_index(&i, index)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
error = git_iterator_current(i, &entry);
|
error = git_iterator_current(i, &entry);
|
||||||
|
21
src/tree.c
21
src/tree.c
@ -55,14 +55,23 @@ static int valid_entry_name(const char *filename)
|
|||||||
strcmp(filename, DOT_GIT) != 0));
|
strcmp(filename, DOT_GIT) != 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_tree_entry_cmp(const git_tree_entry *e1, const git_tree_entry *e2)
|
||||||
|
{
|
||||||
|
return git_path_cmp(
|
||||||
|
e1->filename, e1->filename_len, git_tree_entry__is_tree(e1),
|
||||||
|
e2->filename, e2->filename_len, git_tree_entry__is_tree(e2));
|
||||||
|
}
|
||||||
|
|
||||||
|
int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2)
|
||||||
|
{
|
||||||
|
return git_path_icmp(
|
||||||
|
e1->filename, e1->filename_len, git_tree_entry__is_tree(e1),
|
||||||
|
e2->filename, e2->filename_len, git_tree_entry__is_tree(e2));
|
||||||
|
}
|
||||||
|
|
||||||
static int entry_sort_cmp(const void *a, const void *b)
|
static int entry_sort_cmp(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
const git_tree_entry *entry_a = (const git_tree_entry *)(a);
|
return git_tree_entry_cmp((const git_tree_entry *)a, (const git_tree_entry *)b);
|
||||||
const git_tree_entry *entry_b = (const git_tree_entry *)(b);
|
|
||||||
|
|
||||||
return git_path_cmp(
|
|
||||||
entry_a->filename, entry_a->filename_len, git_tree_entry__is_tree(entry_a),
|
|
||||||
entry_b->filename, entry_b->filename_len, git_tree_entry__is_tree(entry_b));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static git_tree_entry *alloc_entry(const char *filename)
|
static git_tree_entry *alloc_entry(const char *filename)
|
||||||
|
@ -39,6 +39,8 @@ GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e)
|
|||||||
return (S_ISDIR(e->attr) && !S_ISGITLINK(e->attr));
|
return (S_ISDIR(e->attr) && !S_ISGITLINK(e->attr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2);
|
||||||
|
|
||||||
void git_tree__free(git_tree *tree);
|
void git_tree__free(git_tree *tree);
|
||||||
int git_tree__parse(git_tree *tree, git_odb_object *obj);
|
int git_tree__parse(git_tree *tree, git_odb_object *obj);
|
||||||
|
|
||||||
|
60
src/tsort.c
60
src/tsort.c
@ -23,9 +23,8 @@
|
|||||||
# define MIN(x,y) (((x) < (y) ? (x) : (y)))
|
# define MIN(x,y) (((x) < (y) ? (x) : (y)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef int (*cmp_ptr_t)(const void *, const void *);
|
static int binsearch(
|
||||||
|
void **dst, const void *x, size_t size, git__tsort_r_cmp cmp, void *payload)
|
||||||
static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
|
|
||||||
{
|
{
|
||||||
int l, c, r;
|
int l, c, r;
|
||||||
void *lx, *cx;
|
void *lx, *cx;
|
||||||
@ -38,12 +37,12 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
|
|||||||
lx = dst[l];
|
lx = dst[l];
|
||||||
|
|
||||||
/* check for beginning conditions */
|
/* check for beginning conditions */
|
||||||
if (cmp(x, lx) < 0)
|
if (cmp(x, lx, payload) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
else if (cmp(x, lx) == 0) {
|
else if (cmp(x, lx, payload) == 0) {
|
||||||
int i = 1;
|
int i = 1;
|
||||||
while (cmp(x, dst[i]) == 0)
|
while (cmp(x, dst[i], payload) == 0)
|
||||||
i++;
|
i++;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@ -51,7 +50,7 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
|
|||||||
/* guaranteed not to be >= rx */
|
/* guaranteed not to be >= rx */
|
||||||
cx = dst[c];
|
cx = dst[c];
|
||||||
while (1) {
|
while (1) {
|
||||||
const int val = cmp(x, cx);
|
const int val = cmp(x, cx, payload);
|
||||||
if (val < 0) {
|
if (val < 0) {
|
||||||
if (c - l <= 1) return c;
|
if (c - l <= 1) return c;
|
||||||
r = c;
|
r = c;
|
||||||
@ -62,7 +61,7 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
|
|||||||
} else {
|
} else {
|
||||||
do {
|
do {
|
||||||
cx = dst[++c];
|
cx = dst[++c];
|
||||||
} while (cmp(x, cx) == 0);
|
} while (cmp(x, cx, payload) == 0);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
c = l + ((r - l) >> 1);
|
c = l + ((r - l) >> 1);
|
||||||
@ -71,7 +70,8 @@ static int binsearch(void **dst, const void *x, size_t size, cmp_ptr_t cmp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Binary insertion sort, but knowing that the first "start" entries are sorted. Used in timsort. */
|
/* Binary insertion sort, but knowing that the first "start" entries are sorted. Used in timsort. */
|
||||||
static void bisort(void **dst, size_t start, size_t size, cmp_ptr_t cmp)
|
static void bisort(
|
||||||
|
void **dst, size_t start, size_t size, git__tsort_r_cmp cmp, void *payload)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
void *x;
|
void *x;
|
||||||
@ -80,12 +80,12 @@ static void bisort(void **dst, size_t start, size_t size, cmp_ptr_t cmp)
|
|||||||
for (i = start; i < size; i++) {
|
for (i = start; i < size; i++) {
|
||||||
int j;
|
int j;
|
||||||
/* If this entry is already correct, just move along */
|
/* If this entry is already correct, just move along */
|
||||||
if (cmp(dst[i - 1], dst[i]) <= 0)
|
if (cmp(dst[i - 1], dst[i], payload) <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Else we need to find the right place, shift everything over, and squeeze in */
|
/* Else we need to find the right place, shift everything over, and squeeze in */
|
||||||
x = dst[i];
|
x = dst[i];
|
||||||
location = binsearch(dst, x, i, cmp);
|
location = binsearch(dst, x, i, cmp, payload);
|
||||||
for (j = (int)i - 1; j >= location; j--) {
|
for (j = (int)i - 1; j >= location; j--) {
|
||||||
dst[j + 1] = dst[j];
|
dst[j + 1] = dst[j];
|
||||||
}
|
}
|
||||||
@ -102,7 +102,8 @@ struct tsort_run {
|
|||||||
|
|
||||||
struct tsort_store {
|
struct tsort_store {
|
||||||
size_t alloc;
|
size_t alloc;
|
||||||
cmp_ptr_t cmp;
|
git__tsort_r_cmp cmp;
|
||||||
|
void *payload;
|
||||||
void **storage;
|
void **storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -118,7 +119,8 @@ static void reverse_elements(void **dst, ssize_t start, ssize_t end)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t count_run(void **dst, ssize_t start, ssize_t size, struct tsort_store *store)
|
static ssize_t count_run(
|
||||||
|
void **dst, ssize_t start, ssize_t size, struct tsort_store *store)
|
||||||
{
|
{
|
||||||
ssize_t curr = start + 2;
|
ssize_t curr = start + 2;
|
||||||
|
|
||||||
@ -126,7 +128,7 @@ static ssize_t count_run(void **dst, ssize_t start, ssize_t size, struct tsort_s
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (start >= size - 2) {
|
if (start >= size - 2) {
|
||||||
if (store->cmp(dst[size - 2], dst[size - 1]) > 0) {
|
if (store->cmp(dst[size - 2], dst[size - 1], store->payload) > 0) {
|
||||||
void *tmp = dst[size - 1];
|
void *tmp = dst[size - 1];
|
||||||
dst[size - 1] = dst[size - 2];
|
dst[size - 1] = dst[size - 2];
|
||||||
dst[size - 2] = tmp;
|
dst[size - 2] = tmp;
|
||||||
@ -135,13 +137,15 @@ static ssize_t count_run(void **dst, ssize_t start, ssize_t size, struct tsort_s
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (store->cmp(dst[start], dst[start + 1]) <= 0) {
|
if (store->cmp(dst[start], dst[start + 1], store->payload) <= 0) {
|
||||||
while (curr < size - 1 && store->cmp(dst[curr - 1], dst[curr]) <= 0)
|
while (curr < size - 1 &&
|
||||||
|
store->cmp(dst[curr - 1], dst[curr], store->payload) <= 0)
|
||||||
curr++;
|
curr++;
|
||||||
|
|
||||||
return curr - start;
|
return curr - start;
|
||||||
} else {
|
} else {
|
||||||
while (curr < size - 1 && store->cmp(dst[curr - 1], dst[curr]) > 0)
|
while (curr < size - 1 &&
|
||||||
|
store->cmp(dst[curr - 1], dst[curr], store->payload) > 0)
|
||||||
curr++;
|
curr++;
|
||||||
|
|
||||||
/* reverse in-place */
|
/* reverse in-place */
|
||||||
@ -219,7 +223,7 @@ static void merge(void **dst, const struct tsort_run *stack, ssize_t stack_curr,
|
|||||||
|
|
||||||
for (k = curr; k < curr + A + B; k++) {
|
for (k = curr; k < curr + A + B; k++) {
|
||||||
if ((i < A) && (j < curr + A + B)) {
|
if ((i < A) && (j < curr + A + B)) {
|
||||||
if (store->cmp(storage[i], dst[j]) <= 0)
|
if (store->cmp(storage[i], dst[j], store->payload) <= 0)
|
||||||
dst[k] = storage[i++];
|
dst[k] = storage[i++];
|
||||||
else
|
else
|
||||||
dst[k] = dst[j++];
|
dst[k] = dst[j++];
|
||||||
@ -235,7 +239,7 @@ static void merge(void **dst, const struct tsort_run *stack, ssize_t stack_curr,
|
|||||||
|
|
||||||
for (k = curr + A + B - 1; k >= curr; k--) {
|
for (k = curr + A + B - 1; k >= curr; k--) {
|
||||||
if ((i >= 0) && (j >= curr)) {
|
if ((i >= 0) && (j >= curr)) {
|
||||||
if (store->cmp(dst[j], storage[i]) > 0)
|
if (store->cmp(dst[j], storage[i], store->payload) > 0)
|
||||||
dst[k] = dst[j--];
|
dst[k] = dst[j--];
|
||||||
else
|
else
|
||||||
dst[k] = storage[i--];
|
dst[k] = storage[i--];
|
||||||
@ -307,7 +311,7 @@ static ssize_t collapse(void **dst, struct tsort_run *stack, ssize_t stack_curr,
|
|||||||
if (run < minrun) run = minrun;\
|
if (run < minrun) run = minrun;\
|
||||||
if (run > (ssize_t)size - curr) run = size - curr;\
|
if (run > (ssize_t)size - curr) run = size - curr;\
|
||||||
if (run > len) {\
|
if (run > len) {\
|
||||||
bisort(&dst[curr], len, run, cmp);\
|
bisort(&dst[curr], len, run, cmp, payload);\
|
||||||
len = run;\
|
len = run;\
|
||||||
}\
|
}\
|
||||||
run_stack[stack_curr].start = curr;\
|
run_stack[stack_curr].start = curr;\
|
||||||
@ -329,7 +333,8 @@ static ssize_t collapse(void **dst, struct tsort_run *stack, ssize_t stack_curr,
|
|||||||
}\
|
}\
|
||||||
while (0)
|
while (0)
|
||||||
|
|
||||||
void git__tsort(void **dst, size_t size, cmp_ptr_t cmp)
|
void git__tsort_r(
|
||||||
|
void **dst, size_t size, git__tsort_r_cmp cmp, void *payload)
|
||||||
{
|
{
|
||||||
struct tsort_store _store, *store = &_store;
|
struct tsort_store _store, *store = &_store;
|
||||||
struct tsort_run run_stack[128];
|
struct tsort_run run_stack[128];
|
||||||
@ -340,7 +345,7 @@ void git__tsort(void **dst, size_t size, cmp_ptr_t cmp)
|
|||||||
ssize_t minrun;
|
ssize_t minrun;
|
||||||
|
|
||||||
if (size < 64) {
|
if (size < 64) {
|
||||||
bisort(dst, 1, size, cmp);
|
bisort(dst, 1, size, cmp, payload);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,6 +356,7 @@ void git__tsort(void **dst, size_t size, cmp_ptr_t cmp)
|
|||||||
store->alloc = 0;
|
store->alloc = 0;
|
||||||
store->storage = NULL;
|
store->storage = NULL;
|
||||||
store->cmp = cmp;
|
store->cmp = cmp;
|
||||||
|
store->payload = payload;
|
||||||
|
|
||||||
PUSH_NEXT();
|
PUSH_NEXT();
|
||||||
PUSH_NEXT();
|
PUSH_NEXT();
|
||||||
@ -365,3 +371,13 @@ void git__tsort(void **dst, size_t size, cmp_ptr_t cmp)
|
|||||||
PUSH_NEXT();
|
PUSH_NEXT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tsort_r_cmp(const void *a, const void *b, void *payload)
|
||||||
|
{
|
||||||
|
return ((git__tsort_cmp)payload)(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void git__tsort(void **dst, size_t size, git__tsort_cmp cmp)
|
||||||
|
{
|
||||||
|
git__tsort_r(dst, size, tsort_r_cmp, cmp);
|
||||||
|
}
|
||||||
|
31
src/util.c
31
src/util.c
@ -493,6 +493,37 @@ int git__bsearch(
|
|||||||
return (cmp == 0) ? 0 : -1;
|
return (cmp == 0) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git__bsearch_r(
|
||||||
|
void **array,
|
||||||
|
size_t array_len,
|
||||||
|
const void *key,
|
||||||
|
int (*compare_r)(const void *, const void *, void *),
|
||||||
|
void *payload,
|
||||||
|
size_t *position)
|
||||||
|
{
|
||||||
|
unsigned int lim;
|
||||||
|
int cmp = -1;
|
||||||
|
void **part, **base = array;
|
||||||
|
|
||||||
|
for (lim = (unsigned int)array_len; lim != 0; lim >>= 1) {
|
||||||
|
part = base + (lim >> 1);
|
||||||
|
cmp = (*compare_r)(key, *part, payload);
|
||||||
|
if (cmp == 0) {
|
||||||
|
base = part;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (cmp > 0) { /* key > p; take right partition */
|
||||||
|
base = part + 1;
|
||||||
|
lim--;
|
||||||
|
} /* else take left partition */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position)
|
||||||
|
*position = (base - array);
|
||||||
|
|
||||||
|
return (cmp == 0) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A strcmp wrapper
|
* A strcmp wrapper
|
||||||
*
|
*
|
||||||
|
20
src/util.h
20
src/util.h
@ -119,7 +119,15 @@ GIT_INLINE(const char *) git__next_line(const char *s)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void git__tsort(void **dst, size_t size, int (*cmp)(const void *, const void *));
|
typedef int (*git__tsort_cmp)(const void *a, const void *b);
|
||||||
|
|
||||||
|
extern void git__tsort(void **dst, size_t size, git__tsort_cmp cmp);
|
||||||
|
|
||||||
|
typedef int (*git__tsort_r_cmp)(const void *a, const void *b, void *payload);
|
||||||
|
|
||||||
|
extern void git__tsort_r(
|
||||||
|
void **dst, size_t size, git__tsort_r_cmp cmp, void *payload);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param position If non-NULL, this will be set to the position where the
|
* @param position If non-NULL, this will be set to the position where the
|
||||||
@ -130,7 +138,15 @@ extern int git__bsearch(
|
|||||||
void **array,
|
void **array,
|
||||||
size_t array_len,
|
size_t array_len,
|
||||||
const void *key,
|
const void *key,
|
||||||
int (*compare)(const void *, const void *),
|
int (*compare)(const void *key, const void *element),
|
||||||
|
size_t *position);
|
||||||
|
|
||||||
|
extern int git__bsearch_r(
|
||||||
|
void **array,
|
||||||
|
size_t array_len,
|
||||||
|
const void *key,
|
||||||
|
int (*compare_r)(const void *key, const void *element, void *payload),
|
||||||
|
void *payload,
|
||||||
size_t *position);
|
size_t *position);
|
||||||
|
|
||||||
extern int git__strcmp_cb(const void *a, const void *b);
|
extern int git__strcmp_cb(const void *a, const void *b);
|
||||||
|
@ -35,7 +35,8 @@ static void tree_iterator_test(
|
|||||||
git_repository *repo = cl_git_sandbox_init(sandbox);
|
git_repository *repo = cl_git_sandbox_init(sandbox);
|
||||||
|
|
||||||
cl_assert(t = resolve_commit_oid_to_tree(repo, treeish));
|
cl_assert(t = resolve_commit_oid_to_tree(repo, treeish));
|
||||||
cl_git_pass(git_iterator_for_tree_range(&i, t, start, end));
|
cl_git_pass(git_iterator_for_tree_range(
|
||||||
|
&i, t, GIT_ITERATOR_DONT_IGNORE_CASE, start, end));
|
||||||
|
|
||||||
/* test loop */
|
/* test loop */
|
||||||
cl_git_pass(git_iterator_current(i, &entry));
|
cl_git_pass(git_iterator_current(i, &entry));
|
||||||
@ -304,7 +305,8 @@ void test_diff_iterator__tree_special_functions(void)
|
|||||||
repo, "24fa9a9fc4e202313e24b648087495441dab432b");
|
repo, "24fa9a9fc4e202313e24b648087495441dab432b");
|
||||||
cl_assert(t != NULL);
|
cl_assert(t != NULL);
|
||||||
|
|
||||||
cl_git_pass(git_iterator_for_tree_range(&i, t, NULL, NULL));
|
cl_git_pass(git_iterator_for_tree_range(
|
||||||
|
&i, t, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL));
|
||||||
cl_git_pass(git_iterator_current(i, &entry));
|
cl_git_pass(git_iterator_current(i, &entry));
|
||||||
|
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
@ -355,12 +357,14 @@ static void index_iterator_test(
|
|||||||
const char **expected_names,
|
const char **expected_names,
|
||||||
const char **expected_oids)
|
const char **expected_oids)
|
||||||
{
|
{
|
||||||
|
git_index *index;
|
||||||
git_iterator *i;
|
git_iterator *i;
|
||||||
const git_index_entry *entry;
|
const git_index_entry *entry;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
git_repository *repo = cl_git_sandbox_init(sandbox);
|
git_repository *repo = cl_git_sandbox_init(sandbox);
|
||||||
|
|
||||||
cl_git_pass(git_iterator_for_repo_index_range(&i, repo, start, end));
|
cl_git_pass(git_repository_index(&index, repo));
|
||||||
|
cl_git_pass(git_iterator_for_index_range(&i, index, 0, start, end));
|
||||||
cl_git_pass(git_iterator_current(i, &entry));
|
cl_git_pass(git_iterator_current(i, &entry));
|
||||||
|
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
@ -378,6 +382,7 @@ static void index_iterator_test(
|
|||||||
}
|
}
|
||||||
|
|
||||||
git_iterator_free(i);
|
git_iterator_free(i);
|
||||||
|
git_index_free(index);
|
||||||
|
|
||||||
cl_assert_equal_i(expected_count, count);
|
cl_assert_equal_i(expected_count, count);
|
||||||
}
|
}
|
||||||
@ -533,7 +538,7 @@ static void workdir_iterator_test(
|
|||||||
int count = 0, count_all = 0, count_all_post_reset = 0;
|
int count = 0, count_all = 0, count_all_post_reset = 0;
|
||||||
git_repository *repo = cl_git_sandbox_init(sandbox);
|
git_repository *repo = cl_git_sandbox_init(sandbox);
|
||||||
|
|
||||||
cl_git_pass(git_iterator_for_workdir_range(&i, repo, start, end));
|
cl_git_pass(git_iterator_for_workdir_range(&i, repo, 0, start, end));
|
||||||
cl_git_pass(git_iterator_current(i, &entry));
|
cl_git_pass(git_iterator_current(i, &entry));
|
||||||
|
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
@ -731,7 +736,7 @@ void test_diff_iterator__workdir_builtin_ignores(void)
|
|||||||
cl_git_mkfile("attr/sub/.git", "whatever");
|
cl_git_mkfile("attr/sub/.git", "whatever");
|
||||||
|
|
||||||
cl_git_pass(
|
cl_git_pass(
|
||||||
git_iterator_for_workdir_range(&i, repo, "dir", "sub/sub/file"));
|
git_iterator_for_workdir_range(&i, repo, 0, "dir", "sub/sub/file"));
|
||||||
cl_git_pass(git_iterator_current(i, &entry));
|
cl_git_pass(git_iterator_current(i, &entry));
|
||||||
|
|
||||||
for (idx = 0; entry != NULL; ++idx) {
|
for (idx = 0; entry != NULL; ++idx) {
|
||||||
@ -750,3 +755,155 @@ void test_diff_iterator__workdir_builtin_ignores(void)
|
|||||||
|
|
||||||
git_iterator_free(i);
|
git_iterator_free(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void check_wd_first_through_third_range(
|
||||||
|
git_repository *repo, const char *start, const char *end)
|
||||||
|
{
|
||||||
|
git_iterator *i;
|
||||||
|
const git_index_entry *entry;
|
||||||
|
int idx;
|
||||||
|
static const char *expected[] = { "FIRST", "second", "THIRD", NULL };
|
||||||
|
|
||||||
|
cl_git_pass(git_iterator_for_workdir_range(
|
||||||
|
&i, repo, GIT_ITERATOR_IGNORE_CASE, start, end));
|
||||||
|
cl_git_pass(git_iterator_current(i, &entry));
|
||||||
|
|
||||||
|
for (idx = 0; entry != NULL; ++idx) {
|
||||||
|
cl_assert_equal_s(expected[idx], entry->path);
|
||||||
|
|
||||||
|
if (S_ISDIR(entry->mode))
|
||||||
|
cl_git_pass(git_iterator_advance_into_directory(i, &entry));
|
||||||
|
else
|
||||||
|
cl_git_pass(git_iterator_advance(i, &entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_assert(expected[idx] == NULL);
|
||||||
|
|
||||||
|
git_iterator_free(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_diff_iterator__workdir_handles_icase_range(void)
|
||||||
|
{
|
||||||
|
git_repository *repo;
|
||||||
|
|
||||||
|
repo = cl_git_sandbox_init("empty_standard_repo");
|
||||||
|
cl_git_remove_placeholders(git_repository_path(repo), "dummy-marker.txt");
|
||||||
|
|
||||||
|
cl_git_mkfile("empty_standard_repo/before", "whatever\n");
|
||||||
|
cl_git_mkfile("empty_standard_repo/FIRST", "whatever\n");
|
||||||
|
cl_git_mkfile("empty_standard_repo/second", "whatever\n");
|
||||||
|
cl_git_mkfile("empty_standard_repo/THIRD", "whatever\n");
|
||||||
|
cl_git_mkfile("empty_standard_repo/zafter", "whatever\n");
|
||||||
|
cl_git_mkfile("empty_standard_repo/Zlast", "whatever\n");
|
||||||
|
|
||||||
|
check_wd_first_through_third_range(repo, "first", "third");
|
||||||
|
check_wd_first_through_third_range(repo, "FIRST", "THIRD");
|
||||||
|
check_wd_first_through_third_range(repo, "first", "THIRD");
|
||||||
|
check_wd_first_through_third_range(repo, "FIRST", "third");
|
||||||
|
check_wd_first_through_third_range(repo, "FirSt", "tHiRd");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_tree_range(
|
||||||
|
git_repository *repo,
|
||||||
|
const char *start,
|
||||||
|
const char *end,
|
||||||
|
bool ignore_case,
|
||||||
|
int expected_count)
|
||||||
|
{
|
||||||
|
git_tree *head;
|
||||||
|
git_iterator *i;
|
||||||
|
const git_index_entry *entry;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
cl_git_pass(git_repository_head_tree(&head, repo));
|
||||||
|
|
||||||
|
cl_git_pass(git_iterator_for_tree_range(
|
||||||
|
&i, head,
|
||||||
|
ignore_case ? GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE,
|
||||||
|
start, end));
|
||||||
|
|
||||||
|
cl_git_pass(git_iterator_current(i, &entry));
|
||||||
|
|
||||||
|
for (count = 0; entry != NULL; ) {
|
||||||
|
++count;
|
||||||
|
cl_git_pass(git_iterator_advance(i, &entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_assert_equal_i(expected_count, count);
|
||||||
|
|
||||||
|
git_iterator_free(i);
|
||||||
|
git_tree_free(head);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_diff_iterator__tree_handles_icase_range(void)
|
||||||
|
{
|
||||||
|
git_repository *repo;
|
||||||
|
|
||||||
|
repo = cl_git_sandbox_init("testrepo");
|
||||||
|
|
||||||
|
check_tree_range(repo, "B", "C", false, 0);
|
||||||
|
check_tree_range(repo, "B", "C", true, 1);
|
||||||
|
check_tree_range(repo, "a", "z", false, 3);
|
||||||
|
check_tree_range(repo, "a", "z", true, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_index_range(
|
||||||
|
git_repository *repo,
|
||||||
|
const char *start,
|
||||||
|
const char *end,
|
||||||
|
bool ignore_case,
|
||||||
|
int expected_count)
|
||||||
|
{
|
||||||
|
git_index *index;
|
||||||
|
git_iterator *i;
|
||||||
|
const git_index_entry *entry;
|
||||||
|
int count, caps;
|
||||||
|
bool is_ignoring_case;
|
||||||
|
|
||||||
|
cl_git_pass(git_repository_index(&index, repo));
|
||||||
|
|
||||||
|
caps = git_index_caps(index);
|
||||||
|
is_ignoring_case = ((caps & GIT_INDEXCAP_IGNORE_CASE) != 0);
|
||||||
|
|
||||||
|
if (ignore_case != is_ignoring_case)
|
||||||
|
cl_git_pass(git_index_set_caps(index, caps ^ GIT_INDEXCAP_IGNORE_CASE));
|
||||||
|
|
||||||
|
cl_git_pass(git_iterator_for_index_range(&i, index, 0, start, end));
|
||||||
|
|
||||||
|
cl_assert(git_iterator_ignore_case(i) == ignore_case);
|
||||||
|
|
||||||
|
cl_git_pass(git_iterator_current(i, &entry));
|
||||||
|
|
||||||
|
for (count = 0; entry != NULL; ) {
|
||||||
|
++count;
|
||||||
|
cl_git_pass(git_iterator_advance(i, &entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_assert_equal_i(expected_count, count);
|
||||||
|
|
||||||
|
git_iterator_free(i);
|
||||||
|
git_index_free(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_diff_iterator__index_handles_icase_range(void)
|
||||||
|
{
|
||||||
|
git_repository *repo;
|
||||||
|
git_index *index;
|
||||||
|
git_tree *head;
|
||||||
|
|
||||||
|
repo = cl_git_sandbox_init("testrepo");
|
||||||
|
|
||||||
|
/* reset index to match HEAD */
|
||||||
|
cl_git_pass(git_repository_head_tree(&head, repo));
|
||||||
|
cl_git_pass(git_repository_index(&index, repo));
|
||||||
|
cl_git_pass(git_index_read_tree(index, head));
|
||||||
|
cl_git_pass(git_index_write(index));
|
||||||
|
git_tree_free(head);
|
||||||
|
git_index_free(index);
|
||||||
|
|
||||||
|
/* do some ranged iterator checks toggling case sensitivity */
|
||||||
|
check_index_range(repo, "B", "C", false, 0);
|
||||||
|
check_index_range(repo, "B", "C", true, 1);
|
||||||
|
check_index_range(repo, "a", "z", false, 3);
|
||||||
|
check_index_range(repo, "a", "z", true, 4);
|
||||||
|
}
|
||||||
|
@ -580,3 +580,90 @@ void test_status_worktree__conflicted_item(void)
|
|||||||
git_index_free(index);
|
git_index_free(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void stage_and_commit(git_repository *repo, const char *path)
|
||||||
|
{
|
||||||
|
git_oid tree_oid, commit_oid;
|
||||||
|
git_tree *tree;
|
||||||
|
git_signature *signature;
|
||||||
|
git_index *index;
|
||||||
|
|
||||||
|
cl_git_pass(git_repository_index(&index, repo));
|
||||||
|
cl_git_pass(git_index_add_from_workdir(index, path));
|
||||||
|
cl_git_pass(git_index_write(index));
|
||||||
|
|
||||||
|
cl_git_pass(git_index_write_tree(&tree_oid, index));
|
||||||
|
git_index_free(index);
|
||||||
|
|
||||||
|
cl_git_pass(git_tree_lookup(&tree, repo, &tree_oid));
|
||||||
|
|
||||||
|
cl_git_pass(git_signature_new(&signature, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60));
|
||||||
|
|
||||||
|
cl_git_pass(git_commit_create_v(
|
||||||
|
&commit_oid,
|
||||||
|
repo,
|
||||||
|
"HEAD",
|
||||||
|
signature,
|
||||||
|
signature,
|
||||||
|
NULL,
|
||||||
|
"Initial commit\n\0",
|
||||||
|
tree,
|
||||||
|
0));
|
||||||
|
|
||||||
|
git_tree_free(tree);
|
||||||
|
git_signature_free(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_ignore_case(
|
||||||
|
bool should_ignore_case,
|
||||||
|
int expected_lower_cased_file_status,
|
||||||
|
int expected_camel_cased_file_status)
|
||||||
|
{
|
||||||
|
git_config *config;
|
||||||
|
unsigned int status;
|
||||||
|
git_buf lower_case_path = GIT_BUF_INIT, camel_case_path = GIT_BUF_INIT;
|
||||||
|
git_repository *repo, *repo2;
|
||||||
|
|
||||||
|
repo = cl_git_sandbox_init("empty_standard_repo");
|
||||||
|
cl_git_remove_placeholders(git_repository_path(repo), "dummy-marker.txt");
|
||||||
|
|
||||||
|
cl_git_pass(git_repository_config(&config, repo));
|
||||||
|
cl_git_pass(git_config_set_bool(config, "core.ignorecase", should_ignore_case));
|
||||||
|
git_config_free(config);
|
||||||
|
|
||||||
|
cl_git_pass(git_buf_joinpath(&lower_case_path,
|
||||||
|
git_repository_workdir(repo), "plop"));
|
||||||
|
|
||||||
|
cl_git_mkfile(git_buf_cstr(&lower_case_path), "");
|
||||||
|
|
||||||
|
stage_and_commit(repo, "plop");
|
||||||
|
|
||||||
|
cl_git_pass(git_repository_open(&repo2, "./empty_standard_repo"));
|
||||||
|
|
||||||
|
cl_git_pass(git_status_file(&status, repo2, "plop"));
|
||||||
|
cl_assert_equal_i(GIT_STATUS_CURRENT, status);
|
||||||
|
|
||||||
|
cl_git_pass(git_buf_joinpath(&camel_case_path,
|
||||||
|
git_repository_workdir(repo), "Plop"));
|
||||||
|
|
||||||
|
cl_git_pass(p_rename(git_buf_cstr(&lower_case_path), git_buf_cstr(&camel_case_path)));
|
||||||
|
|
||||||
|
cl_git_pass(git_status_file(&status, repo2, "plop"));
|
||||||
|
cl_assert_equal_i(expected_lower_cased_file_status, status);
|
||||||
|
|
||||||
|
cl_git_pass(git_status_file(&status, repo2, "Plop"));
|
||||||
|
cl_assert_equal_i(expected_camel_cased_file_status, status);
|
||||||
|
|
||||||
|
git_repository_free(repo2);
|
||||||
|
git_buf_free(&lower_case_path);
|
||||||
|
git_buf_free(&camel_case_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_status_worktree__file_status_honors_core_ignorecase_true(void)
|
||||||
|
{
|
||||||
|
assert_ignore_case(true, GIT_STATUS_CURRENT, GIT_STATUS_CURRENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_status_worktree__file_status_honors_core_ignorecase_false(void)
|
||||||
|
{
|
||||||
|
assert_ignore_case(false, GIT_STATUS_WT_DELETED, GIT_STATUS_WT_NEW);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user