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);