@matheusbsbs / matheus-bagliano / commits / 61cf282045
Fork 0

pathspec: add match_pathspec_depth()

match_pathspec_depth() is a clone of match_pathspec() except that it can take depth limit. Computation is a bit lighter compared to match_pathspec() because it's usually precomputed and stored in struct pathspec. In long term, match_pathspec() and match_one() should be removed in favor of this function. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Dec 15, 2010 at 22:02 UTC 61cf28204508c095a68e7a9cb6307ca2a27112c9
2 files changed +92
dir.c
+89
@@ -199,6 +199,95 @@ int match_pathspec(const char **pathspec, const char *name, int namelen,
199 return retval;
200 }
201
202 +/*
203 + * Does 'match' match the given name?
204 + * A match is found if
205 + *
206 + * (1) the 'match' string is leading directory of 'name', or
207 + * (2) the 'match' string is a wildcard and matches 'name', or
208 + * (3) the 'match' string is exactly the same as 'name'.
209 + *
210 + * and the return value tells which case it was.
211 + *
212 + * It returns 0 when there is no match.
213 + */
214 +static int match_pathspec_item(const struct pathspec_item *item, int prefix,
215 + const char *name, int namelen)
216 +{
217 + /* name/namelen has prefix cut off by caller */
218 + const char *match = item->match + prefix;
219 + int matchlen = item->len - prefix;
220 +
221 + /* If the match was just the prefix, we matched */
222 + if (!*match)
223 + return MATCHED_RECURSIVELY;
224 +
225 + if (matchlen <= namelen && !strncmp(match, name, matchlen)) {
226 + if (matchlen == namelen)
227 + return MATCHED_EXACTLY;
228 +
229 + if (match[matchlen-1] == '/' || name[matchlen] == '/')
230 + return MATCHED_RECURSIVELY;
231 + }
232 +
233 + if (item->has_wildcard && !fnmatch(match, name, 0))
234 + return MATCHED_FNMATCH;
235 +
236 + return 0;
237 +}
238 +
239 +/*
240 + * Given a name and a list of pathspecs, see if the name matches
241 + * any of the pathspecs. The caller is also interested in seeing
242 + * all pathspec matches some names it calls this function with
243 + * (otherwise the user could have mistyped the unmatched pathspec),
244 + * and a mark is left in seen[] array for pathspec element that
245 + * actually matched anything.
246 + */
247 +int match_pathspec_depth(const struct pathspec *ps,
248 + const char *name, int namelen,
249 + int prefix, char *seen)
250 +{
251 + int i, retval = 0;
252 +
253 + if (!ps->nr) {
254 + if (!ps->recursive || ps->max_depth == -1)
255 + return MATCHED_RECURSIVELY;
256 +
257 + if (within_depth(name, namelen, 0, ps->max_depth))
258 + return MATCHED_EXACTLY;
259 + else
260 + return 0;
261 + }
262 +
263 + name += prefix;
264 + namelen -= prefix;
265 +
266 + for (i = ps->nr - 1; i >= 0; i--) {
267 + int how;
268 + if (seen && seen[i] == MATCHED_EXACTLY)
269 + continue;
270 + how = match_pathspec_item(ps->items+i, prefix, name, namelen);
271 + if (ps->recursive && ps->max_depth != -1 &&
272 + how && how != MATCHED_FNMATCH) {
273 + int len = ps->items[i].len;
274 + if (name[len] == '/')
275 + len++;
276 + if (within_depth(name+len, namelen-len, 0, ps->max_depth))
277 + how = MATCHED_EXACTLY;
278 + else
279 + how = 0;
280 + }
281 + if (how) {
282 + if (retval < how)
283 + retval = how;
284 + if (seen && seen[i] < how)
285 + seen[i] = how;
286 + }
287 + }
288 + return retval;
289 +}
290 +
291 static int no_wildcard(const char *string)
292 {
293 return string[strcspn(string, "*?[{\\")] == '\0';
dir.h
+3
@@ -65,6 +65,9 @@ struct dir_struct {
65 #define MATCHED_FNMATCH 2
66 #define MATCHED_EXACTLY 3
67 extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);
68 +extern int match_pathspec_depth(const struct pathspec *pathspec,
69 + const char *name, int namelen,
70 + int prefix, char *seen);
71 extern int within_depth(const char *name, int namelen, int depth, int max_depth);
72
73 extern int fill_directory(struct dir_struct *dir, const char **pathspec);