]>
Commit | Line | Data |
---|---|---|
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 |
17 | typedef struct git_iterator git_iterator; |
18 | ||
19 | typedef 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 | 27 | typedef 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 |
48 | typedef 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 |
55 | typedef 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 | 70 | typedef 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 | ||
80 | struct 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 | 105 | extern 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 | 112 | extern 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 | 120 | extern 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 |
126 | extern 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 | 137 | GIT_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 | */ | |
150 | extern int git_iterator_for_filesystem( | |
151 | git_iterator **out, | |
152 | const char *root, | |
ed1c6446 | 153 | git_iterator_options *options); |
ff0ddfa4 | 154 | |
4b181037 RB |
155 | extern 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 | */ |
168 | GIT_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 | 181 | GIT_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 | */ |
202 | GIT_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 | */ | |
218 | GIT_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 |
229 | GIT_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 |
238 | extern int git_iterator_reset_range( |
239 | git_iterator *iter, const char *start, const char *end); | |
169dc616 | 240 | |
22a2d3d5 | 241 | GIT_INLINE(git_iterator_t) git_iterator_type(git_iterator *iter) |
b6c93aef RB |
242 | { |
243 | return iter->type; | |
244 | } | |
245 | ||
9950d27a RB |
246 | GIT_INLINE(git_repository *) git_iterator_owner(git_iterator *iter) |
247 | { | |
248 | return iter->repo; | |
249 | } | |
250 | ||
82a1aab6 ET |
251 | GIT_INLINE(git_index *) git_iterator_index(git_iterator *iter) |
252 | { | |
253 | return iter->index; | |
254 | } | |
255 | ||
134d8c91 RB |
256 | GIT_INLINE(git_iterator_flag_t) git_iterator_flags(git_iterator *iter) |
257 | { | |
258 | return iter->flags; | |
259 | } | |
260 | ||
261 | GIT_INLINE(bool) git_iterator_ignore_case(git_iterator *iter) | |
262 | { | |
263 | return ((iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0); | |
264 | } | |
265 | ||
c25aa7cd | 266 | extern int git_iterator_set_ignore_case( |
9eb9e5fa | 267 | git_iterator *iter, bool ignore_case); |
cc216a01 | 268 | |
b6c93aef | 269 | extern int git_iterator_current_tree_entry( |
9bea03ce | 270 | const git_tree_entry **entry_out, git_iterator *iter); |
b6c93aef | 271 | |
0d64bef9 | 272 | extern int git_iterator_current_parent_tree( |
be30387e | 273 | const git_tree **tree_out, git_iterator *iter, size_t depth); |
0d64bef9 | 274 | |
169dc616 | 275 | extern bool git_iterator_current_is_ignored(git_iterator *iter); |
b6c93aef | 276 | |
f554611a RB |
277 | extern 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 | */ |
284 | extern 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 | 292 | extern git_index *git_iterator_index(git_iterator *iter); |
ff475375 | 293 | |
ac3d33df JK |
294 | typedef 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 | */ | |
302 | extern int git_iterator_foreach( | |
303 | git_iterator *iterator, | |
304 | git_iterator_foreach_cb cb, | |
305 | void *data); | |
306 | ||
8960dc1e ET |
307 | typedef 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 | */ | |
316 | extern 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 |