]>
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" | |
11 | #include "git2/index.h" | |
ec40b7f9 | 12 | #include "vector.h" |
dfbff793 | 13 | #include "buffer.h" |
ff475375 | 14 | #include "ignore.h" |
ec40b7f9 | 15 | |
b6c93aef RB |
16 | typedef struct git_iterator git_iterator; |
17 | ||
18 | typedef enum { | |
134d8c91 RB |
19 | GIT_ITERATOR_TYPE_EMPTY = 0, |
20 | GIT_ITERATOR_TYPE_TREE = 1, | |
21 | GIT_ITERATOR_TYPE_INDEX = 2, | |
22 | GIT_ITERATOR_TYPE_WORKDIR = 3, | |
ff0ddfa4 | 23 | GIT_ITERATOR_TYPE_FS = 4, |
b6c93aef RB |
24 | } git_iterator_type_t; |
25 | ||
134d8c91 | 26 | typedef enum { |
169dc616 | 27 | /** ignore case for entry sort order */ |
2fe54afa | 28 | GIT_ITERATOR_IGNORE_CASE = (1u << 0), |
169dc616 | 29 | /** force case sensitivity for entry sort order */ |
2fe54afa | 30 | GIT_ITERATOR_DONT_IGNORE_CASE = (1u << 1), |
9bea03ce | 31 | /** return tree items in addition to blob items */ |
2fe54afa | 32 | GIT_ITERATOR_INCLUDE_TREES = (1u << 2), |
9bea03ce | 33 | /** don't flatten trees, requiring advance_into (implies INCLUDE_TREES) */ |
2fe54afa RB |
34 | GIT_ITERATOR_DONT_AUTOEXPAND = (1u << 3), |
35 | /** convert precomposed unicode to decomposed unicode */ | |
36 | GIT_ITERATOR_PRECOMPOSE_UNICODE = (1u << 4), | |
aa3af01d ET |
37 | /** include conflicts */ |
38 | GIT_ITERATOR_INCLUDE_CONFLICTS = (1u << 5), | |
134d8c91 RB |
39 | } git_iterator_flag_t; |
40 | ||
f616a36b | 41 | typedef struct { |
169dc616 RB |
42 | int (*current)(const git_index_entry **, git_iterator *); |
43 | int (*advance)(const git_index_entry **, git_iterator *); | |
9bea03ce | 44 | int (*advance_into)(const git_index_entry **, git_iterator *); |
41a82592 | 45 | int (*seek)(git_iterator *, const char *prefix); |
91e7d263 | 46 | int (*reset)(git_iterator *, const char *start, const char *end); |
169dc616 | 47 | int (*at_end)(git_iterator *); |
b6c93aef | 48 | void (*free)(git_iterator *); |
f616a36b RB |
49 | } git_iterator_callbacks; |
50 | ||
51 | struct git_iterator { | |
52 | git_iterator_type_t type; | |
53 | git_iterator_callbacks *cb; | |
54 | git_repository *repo; | |
55 | char *start; | |
56 | char *end; | |
25423d03 | 57 | int (*prefixcomp)(const char *str, const char *prefix); |
9c8ed499 | 58 | size_t stat_calls; |
134d8c91 | 59 | unsigned int flags; |
b6c93aef RB |
60 | }; |
61 | ||
134d8c91 | 62 | extern int git_iterator_for_nothing( |
169dc616 RB |
63 | git_iterator **out, |
64 | git_iterator_flag_t flags, | |
65 | const char *start, | |
66 | const char *end); | |
7e000ab2 | 67 | |
134d8c91 RB |
68 | /* tree iterators will match the ignore_case value from the index of the |
69 | * repository, unless you override with a non-zero flag value | |
70 | */ | |
169dc616 | 71 | extern int git_iterator_for_tree( |
134d8c91 RB |
72 | git_iterator **out, |
73 | git_tree *tree, | |
74 | git_iterator_flag_t flags, | |
75 | const char *start, | |
76 | const char *end); | |
b6c93aef | 77 | |
134d8c91 RB |
78 | /* index iterators will take the ignore_case value from the index; the |
79 | * ignore_case flags are not used | |
80 | */ | |
169dc616 | 81 | extern int git_iterator_for_index( |
134d8c91 RB |
82 | git_iterator **out, |
83 | git_index *index, | |
84 | git_iterator_flag_t flags, | |
85 | const char *start, | |
86 | const char *end); | |
41a82592 | 87 | |
9094ae5a RB |
88 | extern int git_iterator_for_workdir_ext( |
89 | git_iterator **out, | |
90 | git_repository *repo, | |
91 | const char *repo_workdir, | |
62a617dc CMN |
92 | git_index *index, |
93 | git_tree *tree, | |
9094ae5a RB |
94 | git_iterator_flag_t flags, |
95 | const char *start, | |
96 | const char *end); | |
97 | ||
134d8c91 RB |
98 | /* workdir iterators will match the ignore_case value from the index of the |
99 | * repository, unless you override with a non-zero flag value | |
100 | */ | |
9094ae5a | 101 | GIT_INLINE(int) git_iterator_for_workdir( |
134d8c91 RB |
102 | git_iterator **out, |
103 | git_repository *repo, | |
62a617dc CMN |
104 | git_index *index, |
105 | git_tree *tree, | |
134d8c91 RB |
106 | git_iterator_flag_t flags, |
107 | const char *start, | |
9094ae5a RB |
108 | const char *end) |
109 | { | |
62a617dc | 110 | return git_iterator_for_workdir_ext(out, repo, NULL, index, tree, flags, start, end); |
9094ae5a | 111 | } |
41a82592 | 112 | |
ff0ddfa4 RB |
113 | /* for filesystem iterators, you have to explicitly pass in the ignore_case |
114 | * behavior that you desire | |
115 | */ | |
116 | extern int git_iterator_for_filesystem( | |
117 | git_iterator **out, | |
118 | const char *root, | |
119 | git_iterator_flag_t flags, | |
120 | const char *start, | |
121 | const char *end); | |
122 | ||
4b181037 RB |
123 | extern void git_iterator_free(git_iterator *iter); |
124 | ||
169dc616 RB |
125 | /* Return a git_index_entry structure for the current value the iterator |
126 | * is looking at or NULL if the iterator is at the end. | |
127 | * | |
128 | * The entry may noy be fully populated. Tree iterators will only have a | |
129 | * value mode, OID, and path. Workdir iterators will not have an OID (but | |
130 | * you can use `git_iterator_current_oid()` to calculate it on demand). | |
b6c93aef RB |
131 | * |
132 | * You do not need to free the entry. It is still "owned" by the iterator. | |
169dc616 RB |
133 | * Once you call `git_iterator_advance()` then the old entry is no longer |
134 | * guaranteed to be valid - it may be freed or just overwritten in place. | |
b6c93aef RB |
135 | */ |
136 | GIT_INLINE(int) git_iterator_current( | |
169dc616 | 137 | const git_index_entry **entry, git_iterator *iter) |
b6c93aef | 138 | { |
169dc616 | 139 | return iter->cb->current(entry, iter); |
b6c93aef RB |
140 | } |
141 | ||
9bea03ce RB |
142 | /** |
143 | * Advance to the next item for the iterator. | |
144 | * | |
145 | * If GIT_ITERATOR_INCLUDE_TREES is set, this may be a tree item. If | |
146 | * GIT_ITERATOR_DONT_AUTOEXPAND is set, calling this again when on a tree | |
147 | * item will skip over all the items under that tree. | |
148 | */ | |
da337c80 | 149 | GIT_INLINE(int) git_iterator_advance( |
169dc616 | 150 | const git_index_entry **entry, git_iterator *iter) |
b6c93aef | 151 | { |
169dc616 | 152 | return iter->cb->advance(entry, iter); |
b6c93aef RB |
153 | } |
154 | ||
9bea03ce RB |
155 | /** |
156 | * Iterate into a tree item (when GIT_ITERATOR_DONT_AUTOEXPAND is set). | |
157 | * | |
158 | * git_iterator_advance() steps through all items being iterated over | |
159 | * (either with or without trees, depending on GIT_ITERATOR_INCLUDE_TREES), | |
160 | * but if GIT_ITERATOR_DONT_AUTOEXPAND is set, it will skip to the next | |
161 | * sibling of a tree instead of going to the first child of the tree. In | |
162 | * that case, use this function to advance to the first child of the tree. | |
163 | * | |
164 | * If the current item is not a tree, this is a no-op. | |
165 | * | |
cee695ae RB |
166 | * For filesystem and working directory iterators, a tree (i.e. directory) |
167 | * can be empty. In that case, this function returns GIT_ENOTFOUND and | |
168 | * does not advance. That can't happen for tree and index iterators. | |
9bea03ce RB |
169 | */ |
170 | GIT_INLINE(int) git_iterator_advance_into( | |
171 | const git_index_entry **entry, git_iterator *iter) | |
172 | { | |
173 | return iter->cb->advance_into(entry, iter); | |
174 | } | |
175 | ||
cee695ae RB |
176 | /** |
177 | * Advance into a tree or skip over it if it is empty. | |
178 | * | |
179 | * Because `git_iterator_advance_into` may return GIT_ENOTFOUND if the | |
180 | * directory is empty (only with filesystem and working directory | |
181 | * iterators) and a common response is to just call `git_iterator_advance` | |
182 | * when that happens, this bundles the two into a single simple call. | |
183 | */ | |
184 | GIT_INLINE(int) git_iterator_advance_into_or_over( | |
185 | const git_index_entry **entry, git_iterator *iter) | |
186 | { | |
187 | int error = iter->cb->advance_into(entry, iter); | |
188 | if (error == GIT_ENOTFOUND) { | |
189 | giterr_clear(); | |
190 | error = iter->cb->advance(entry, iter); | |
191 | } | |
192 | return error; | |
193 | } | |
194 | ||
195 | /* Seek is currently unimplemented */ | |
41a82592 RB |
196 | GIT_INLINE(int) git_iterator_seek( |
197 | git_iterator *iter, const char *prefix) | |
198 | { | |
f616a36b | 199 | return iter->cb->seek(iter, prefix); |
41a82592 RB |
200 | } |
201 | ||
cee695ae RB |
202 | /** |
203 | * Go back to the start of the iteration. | |
204 | * | |
205 | * This resets the iterator to the start of the iteration. It also allows | |
206 | * you to reset the `start` and `end` pathname boundaries of the iteration | |
207 | * when doing so. | |
208 | */ | |
91e7d263 RB |
209 | GIT_INLINE(int) git_iterator_reset( |
210 | git_iterator *iter, const char *start, const char *end) | |
74fa4bfa | 211 | { |
f616a36b | 212 | return iter->cb->reset(iter, start, end); |
74fa4bfa RB |
213 | } |
214 | ||
cee695ae RB |
215 | /** |
216 | * Check if the iterator is at the end | |
217 | * | |
218 | * @return 0 if not at end, >0 if at end | |
219 | */ | |
169dc616 RB |
220 | GIT_INLINE(int) git_iterator_at_end(git_iterator *iter) |
221 | { | |
222 | return iter->cb->at_end(iter); | |
223 | } | |
224 | ||
b6c93aef RB |
225 | GIT_INLINE(git_iterator_type_t) git_iterator_type(git_iterator *iter) |
226 | { | |
227 | return iter->type; | |
228 | } | |
229 | ||
9950d27a RB |
230 | GIT_INLINE(git_repository *) git_iterator_owner(git_iterator *iter) |
231 | { | |
232 | return iter->repo; | |
233 | } | |
234 | ||
134d8c91 RB |
235 | GIT_INLINE(git_iterator_flag_t) git_iterator_flags(git_iterator *iter) |
236 | { | |
237 | return iter->flags; | |
238 | } | |
239 | ||
240 | GIT_INLINE(bool) git_iterator_ignore_case(git_iterator *iter) | |
241 | { | |
242 | return ((iter->flags & GIT_ITERATOR_IGNORE_CASE) != 0); | |
243 | } | |
244 | ||
cc216a01 RB |
245 | extern int git_iterator_set_ignore_case(git_iterator *iter, bool ignore_case); |
246 | ||
b6c93aef | 247 | extern int git_iterator_current_tree_entry( |
9bea03ce | 248 | const git_tree_entry **entry_out, git_iterator *iter); |
b6c93aef | 249 | |
0d64bef9 | 250 | extern int git_iterator_current_parent_tree( |
9bea03ce | 251 | const git_tree **tree_out, git_iterator *iter, const char *parent_path); |
0d64bef9 | 252 | |
169dc616 | 253 | extern bool git_iterator_current_is_ignored(git_iterator *iter); |
b6c93aef | 254 | |
f554611a RB |
255 | extern bool git_iterator_current_tree_is_ignored(git_iterator *iter); |
256 | ||
41a82592 RB |
257 | extern int git_iterator_cmp( |
258 | git_iterator *iter, const char *path_prefix); | |
259 | ||
dfbff793 | 260 | /** |
169dc616 RB |
261 | * Get full path of the current item from a workdir iterator. This will |
262 | * return NULL for a non-workdir iterator. The git_buf is still owned by | |
263 | * the iterator; this is exposed just for efficiency. | |
dfbff793 RB |
264 | */ |
265 | extern int git_iterator_current_workdir_path( | |
169dc616 | 266 | git_buf **path, git_iterator *iter); |
5cf9875a | 267 | |
169dc616 RB |
268 | /* Return index pointer if index iterator, else NULL */ |
269 | extern git_index *git_iterator_get_index(git_iterator *iter); | |
5cf9875a | 270 | |
219c89d1 RB |
271 | typedef enum { |
272 | GIT_ITERATOR_STATUS_NORMAL = 0, | |
273 | GIT_ITERATOR_STATUS_IGNORED = 1, | |
274 | GIT_ITERATOR_STATUS_EMPTY = 2 | |
275 | } git_iterator_status_t; | |
276 | ||
277 | /* Advance over a directory and check if it contains no files or just | |
278 | * ignored files. | |
279 | * | |
280 | * In a tree or the index, all directories will contain files, but in the | |
281 | * working directory it is possible to have an empty directory tree or a | |
282 | * tree that only contains ignored files. Many Git operations treat these | |
283 | * cases specially. This advances over a directory (presumably an | |
284 | * untracked directory) but checks during the scan if there are any files | |
285 | * and any non-ignored files. | |
37da3685 | 286 | */ |
219c89d1 RB |
287 | extern int git_iterator_advance_over_with_status( |
288 | const git_index_entry **entry, git_iterator_status_t *status, git_iterator *iter); | |
37da3685 | 289 | |
ff475375 CMN |
290 | /** |
291 | * Retrieve the index stored in the iterator. | |
292 | * | |
293 | * Only implemented for the workdir iterator | |
294 | */ | |
295 | extern int git_iterator_index(git_index **out, git_iterator *iter); | |
296 | ||
b6c93aef | 297 | #endif |