]> git.proxmox.com Git - libgit2.git/blame - src/iterator.h
Upload to experimental
[libgit2.git] / src / iterator.h
CommitLineData
b6c93aef 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
b6c93aef
RB
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7#ifndef INCLUDE_iterator_h__
8#define INCLUDE_iterator_h__
9
10#include "common.h"
eae0bfdc 11
b6c93aef 12#include "git2/index.h"
ec40b7f9 13#include "vector.h"
dfbff793 14#include "buffer.h"
ff475375 15#include "ignore.h"
ec40b7f9 16
b6c93aef
RB
17typedef struct git_iterator git_iterator;
18
19typedef enum {
22a2d3d5
UG
20 GIT_ITERATOR_EMPTY = 0,
21 GIT_ITERATOR_TREE = 1,
22 GIT_ITERATOR_INDEX = 2,
23 GIT_ITERATOR_WORKDIR = 3,
24 GIT_ITERATOR_FS = 4,
25} git_iterator_t;
b6c93aef 26
134d8c91 27typedef enum {
169dc616 28 /** ignore case for entry sort order */
2fe54afa 29 GIT_ITERATOR_IGNORE_CASE = (1u << 0),
169dc616 30 /** force case sensitivity for entry sort order */
2fe54afa 31 GIT_ITERATOR_DONT_IGNORE_CASE = (1u << 1),
9bea03ce 32 /** return tree items in addition to blob items */
2fe54afa 33 GIT_ITERATOR_INCLUDE_TREES = (1u << 2),
9bea03ce 34 /** don't flatten trees, requiring advance_into (implies INCLUDE_TREES) */
2fe54afa
RB
35 GIT_ITERATOR_DONT_AUTOEXPAND = (1u << 3),
36 /** convert precomposed unicode to decomposed unicode */
37 GIT_ITERATOR_PRECOMPOSE_UNICODE = (1u << 4),
0e0589fc
ET
38 /** never convert precomposed unicode to decomposed unicode */
39 GIT_ITERATOR_DONT_PRECOMPOSE_UNICODE = (1u << 5),
aa3af01d 40 /** include conflicts */
0e0589fc 41 GIT_ITERATOR_INCLUDE_CONFLICTS = (1u << 6),
eae0bfdc
PP
42 /** descend into symlinked directories */
43 GIT_ITERATOR_DESCEND_SYMLINKS = (1u << 7),
ac3d33df
JK
44 /** hash files in workdir or filesystem iterators */
45 GIT_ITERATOR_INCLUDE_HASH = (1u << 8),
134d8c91
RB
46} git_iterator_flag_t;
47
0e0589fc
ET
48typedef enum {
49 GIT_ITERATOR_STATUS_NORMAL = 0,
50 GIT_ITERATOR_STATUS_IGNORED = 1,
51 GIT_ITERATOR_STATUS_EMPTY = 2,
52 GIT_ITERATOR_STATUS_FILTERED = 3
53} git_iterator_status_t;
54
ed1c6446
ET
55typedef struct {
56 const char *start;
57 const char *end;
58
4a0dbeb0
ET
59 /* paths to include in the iterator (literal). if set, any paths not
60 * listed here will be excluded from iteration.
ef206124 61 */
4a0dbeb0 62 git_strarray pathlist;
ef206124 63
ed1c6446
ET
64 /* flags, from above */
65 unsigned int flags;
66} git_iterator_options;
67
68#define GIT_ITERATOR_OPTIONS_INIT {0}
69
f616a36b 70typedef struct {
169dc616
RB
71 int (*current)(const git_index_entry **, git_iterator *);
72 int (*advance)(const git_index_entry **, git_iterator *);
9bea03ce 73 int (*advance_into)(const git_index_entry **, git_iterator *);
0e0589fc
ET
74 int (*advance_over)(
75 const git_index_entry **, git_iterator_status_t *, git_iterator *);
684b35c4 76 int (*reset)(git_iterator *);
b6c93aef 77 void (*free)(git_iterator *);
f616a36b
RB
78} git_iterator_callbacks;
79
80struct git_iterator {
22a2d3d5 81 git_iterator_t type;
f616a36b 82 git_iterator_callbacks *cb;
82a1aab6 83
f616a36b 84 git_repository *repo;
82a1aab6 85 git_index *index;
0e0589fc 86
f616a36b 87 char *start;
0e0589fc
ET
88 size_t start_len;
89
f616a36b 90 char *end;
0e0589fc
ET
91 size_t end_len;
92
be30387e
ET
93 bool started;
94 bool ended;
4a0dbeb0 95 git_vector pathlist;
d53c8880 96 size_t pathlist_walk_idx;
4a0dbeb0
ET
97 int (*strcomp)(const char *a, const char *b);
98 int (*strncomp)(const char *a, const char *b, size_t n);
25423d03 99 int (*prefixcomp)(const char *str, const char *prefix);
0e0589fc 100 int (*entry_srch)(const void *key, const void *array_member);
9c8ed499 101 size_t stat_calls;
134d8c91 102 unsigned int flags;
b6c93aef
RB
103};
104
134d8c91 105extern int git_iterator_for_nothing(
169dc616 106 git_iterator **out,
ed1c6446 107 git_iterator_options *options);
7e000ab2 108
134d8c91
RB
109/* tree iterators will match the ignore_case value from the index of the
110 * repository, unless you override with a non-zero flag value
111 */
169dc616 112extern int git_iterator_for_tree(
134d8c91
RB
113 git_iterator **out,
114 git_tree *tree,
ed1c6446 115 git_iterator_options *options);
b6c93aef 116
134d8c91
RB
117/* index iterators will take the ignore_case value from the index; the
118 * ignore_case flags are not used
119 */
169dc616 120extern int git_iterator_for_index(
134d8c91 121 git_iterator **out,
3679ebae 122 git_repository *repo,
134d8c91 123 git_index *index,
ed1c6446 124 git_iterator_options *options);
41a82592 125
9094ae5a
RB
126extern int git_iterator_for_workdir_ext(
127 git_iterator **out,
128 git_repository *repo,
129 const char *repo_workdir,
62a617dc
CMN
130 git_index *index,
131 git_tree *tree,
ed1c6446 132 git_iterator_options *options);
9094ae5a 133
134d8c91
RB
134/* workdir iterators will match the ignore_case value from the index of the
135 * repository, unless you override with a non-zero flag value
136 */
9094ae5a 137GIT_INLINE(int) git_iterator_for_workdir(
134d8c91
RB
138 git_iterator **out,
139 git_repository *repo,
62a617dc
CMN
140 git_index *index,
141 git_tree *tree,
ed1c6446 142 git_iterator_options *options)
9094ae5a 143{
ed1c6446 144 return git_iterator_for_workdir_ext(out, repo, NULL, index, tree, options);
9094ae5a 145}
41a82592 146
ff0ddfa4
RB
147/* for filesystem iterators, you have to explicitly pass in the ignore_case
148 * behavior that you desire
149 */
150extern int git_iterator_for_filesystem(
151 git_iterator **out,
152 const char *root,
ed1c6446 153 git_iterator_options *options);
ff0ddfa4 154
4b181037
RB
155extern void git_iterator_free(git_iterator *iter);
156
169dc616
RB
157/* Return a git_index_entry structure for the current value the iterator
158 * is looking at or NULL if the iterator is at the end.
159 *
160 * The entry may noy be fully populated. Tree iterators will only have a
161 * value mode, OID, and path. Workdir iterators will not have an OID (but
162 * you can use `git_iterator_current_oid()` to calculate it on demand).
b6c93aef
RB
163 *
164 * You do not need to free the entry. It is still "owned" by the iterator.
169dc616
RB
165 * Once you call `git_iterator_advance()` then the old entry is no longer
166 * guaranteed to be valid - it may be freed or just overwritten in place.
b6c93aef
RB
167 */
168GIT_INLINE(int) git_iterator_current(
169dc616 169 const git_index_entry **entry, git_iterator *iter)
b6c93aef 170{
169dc616 171 return iter->cb->current(entry, iter);
b6c93aef
RB
172}
173
9bea03ce
RB
174/**
175 * Advance to the next item for the iterator.
176 *
177 * If GIT_ITERATOR_INCLUDE_TREES is set, this may be a tree item. If
178 * GIT_ITERATOR_DONT_AUTOEXPAND is set, calling this again when on a tree
179 * item will skip over all the items under that tree.
180 */
da337c80 181GIT_INLINE(int) git_iterator_advance(
169dc616 182 const git_index_entry **entry, git_iterator *iter)
b6c93aef 183{
169dc616 184 return iter->cb->advance(entry, iter);
b6c93aef
RB
185}
186
9bea03ce
RB
187/**
188 * Iterate into a tree item (when GIT_ITERATOR_DONT_AUTOEXPAND is set).
189 *
190 * git_iterator_advance() steps through all items being iterated over
191 * (either with or without trees, depending on GIT_ITERATOR_INCLUDE_TREES),
192 * but if GIT_ITERATOR_DONT_AUTOEXPAND is set, it will skip to the next
193 * sibling of a tree instead of going to the first child of the tree. In
194 * that case, use this function to advance to the first child of the tree.
195 *
196 * If the current item is not a tree, this is a no-op.
197 *
cee695ae
RB
198 * For filesystem and working directory iterators, a tree (i.e. directory)
199 * can be empty. In that case, this function returns GIT_ENOTFOUND and
200 * does not advance. That can't happen for tree and index iterators.
9bea03ce
RB
201 */
202GIT_INLINE(int) git_iterator_advance_into(
203 const git_index_entry **entry, git_iterator *iter)
204{
205 return iter->cb->advance_into(entry, iter);
206}
207
0e0589fc
ET
208/* Advance over a directory and check if it contains no files or just
209 * ignored files.
210 *
211 * In a tree or the index, all directories will contain files, but in the
212 * working directory it is possible to have an empty directory tree or a
213 * tree that only contains ignored files. Many Git operations treat these
214 * cases specially. This advances over a directory (presumably an
215 * untracked directory) but checks during the scan if there are any files
216 * and any non-ignored files.
217 */
218GIT_INLINE(int) git_iterator_advance_over(
219 const git_index_entry **entry,
220 git_iterator_status_t *status,
221 git_iterator *iter)
222{
247e3b43 223 return iter->cb->advance_over(entry, status, iter);
0e0589fc
ET
224}
225
cee695ae
RB
226/**
227 * Go back to the start of the iteration.
cee695ae 228 */
684b35c4
ET
229GIT_INLINE(int) git_iterator_reset(git_iterator *iter)
230{
231 return iter->cb->reset(iter);
232}
233
234/**
235 * Go back to the start of the iteration after updating the `start` and
236 * `end` pathname boundaries of the iteration.
237 */
9eb9e5fa
ET
238extern int git_iterator_reset_range(
239 git_iterator *iter, const char *start, const char *end);
169dc616 240
22a2d3d5 241GIT_INLINE(git_iterator_t) git_iterator_type(git_iterator *iter)
b6c93aef
RB
242{
243 return iter->type;
244}
245
9950d27a
RB
246GIT_INLINE(git_repository *) git_iterator_owner(git_iterator *iter)
247{
248 return iter->repo;
249}
250
82a1aab6
ET
251GIT_INLINE(git_index *) git_iterator_index(git_iterator *iter)
252{
253 return iter->index;
254}
255
134d8c91
RB
256GIT_INLINE(git_iterator_flag_t) git_iterator_flags(git_iterator *iter)
257{
258 return iter->flags;
259}
260
261GIT_INLINE(bool) git_iterator_ignore_case(git_iterator *iter)
262{
263 return ((iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0);
264}
265
c25aa7cd 266extern int git_iterator_set_ignore_case(
9eb9e5fa 267 git_iterator *iter, bool ignore_case);
cc216a01 268
b6c93aef 269extern int git_iterator_current_tree_entry(
9bea03ce 270 const git_tree_entry **entry_out, git_iterator *iter);
b6c93aef 271
0d64bef9 272extern int git_iterator_current_parent_tree(
be30387e 273 const git_tree **tree_out, git_iterator *iter, size_t depth);
0d64bef9 274
169dc616 275extern bool git_iterator_current_is_ignored(git_iterator *iter);
b6c93aef 276
f554611a
RB
277extern bool git_iterator_current_tree_is_ignored(git_iterator *iter);
278
dfbff793 279/**
169dc616
RB
280 * Get full path of the current item from a workdir iterator. This will
281 * return NULL for a non-workdir iterator. The git_buf is still owned by
282 * the iterator; this is exposed just for efficiency.
dfbff793
RB
283 */
284extern int git_iterator_current_workdir_path(
169dc616 285 git_buf **path, git_iterator *iter);
5cf9875a 286
ff475375
CMN
287/**
288 * Retrieve the index stored in the iterator.
289 *
0e0589fc 290 * Only implemented for the workdir and index iterators.
ff475375 291 */
0e0589fc 292extern git_index *git_iterator_index(git_iterator *iter);
ff475375 293
ac3d33df
JK
294typedef int (*git_iterator_foreach_cb)(
295 const git_index_entry *entry,
296 void *data);
297
298/**
299 * Walk the given iterator and invoke the callback for each path
300 * contained in the iterator.
301 */
302extern int git_iterator_foreach(
303 git_iterator *iterator,
304 git_iterator_foreach_cb cb,
305 void *data);
306
8960dc1e
ET
307typedef int (*git_iterator_walk_cb)(
308 const git_index_entry **entries,
309 void *data);
310
311/**
312 * Walk the given iterators in lock-step. The given callback will be
313 * called for each unique path, with the index entry in each iterator
314 * (or NULL if the given iterator does not contain that path).
315 */
316extern int git_iterator_walk(
317 git_iterator **iterators,
318 size_t cnt,
319 git_iterator_walk_cb cb,
320 void *data);
321
b6c93aef 322#endif