Skip to content

Commit

Permalink
pathspec: add match_pathspec_depth()
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
pclouds authored and gitster committed Feb 3, 2011
1 parent f1a2ddb commit 61cf282
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
89 changes: 89 additions & 0 deletions dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,95 @@ int match_pathspec(const char **pathspec, const char *name, int namelen,
return retval;
}

/*
* Does 'match' match the given name?
* A match is found if
*
* (1) the 'match' string is leading directory of 'name', or
* (2) the 'match' string is a wildcard and matches 'name', or
* (3) the 'match' string is exactly the same as 'name'.
*
* and the return value tells which case it was.
*
* It returns 0 when there is no match.
*/
static int match_pathspec_item(const struct pathspec_item *item, int prefix,
const char *name, int namelen)
{
/* name/namelen has prefix cut off by caller */
const char *match = item->match + prefix;
int matchlen = item->len - prefix;

/* If the match was just the prefix, we matched */
if (!*match)
return MATCHED_RECURSIVELY;

if (matchlen <= namelen && !strncmp(match, name, matchlen)) {
if (matchlen == namelen)
return MATCHED_EXACTLY;

if (match[matchlen-1] == '/' || name[matchlen] == '/')
return MATCHED_RECURSIVELY;
}

if (item->has_wildcard && !fnmatch(match, name, 0))
return MATCHED_FNMATCH;

return 0;
}

/*
* Given a name and a list of pathspecs, see if the name matches
* any of the pathspecs. The caller is also interested in seeing
* all pathspec matches some names it calls this function with
* (otherwise the user could have mistyped the unmatched pathspec),
* and a mark is left in seen[] array for pathspec element that
* actually matched anything.
*/
int match_pathspec_depth(const struct pathspec *ps,
const char *name, int namelen,
int prefix, char *seen)
{
int i, retval = 0;

if (!ps->nr) {
if (!ps->recursive || ps->max_depth == -1)
return MATCHED_RECURSIVELY;

if (within_depth(name, namelen, 0, ps->max_depth))
return MATCHED_EXACTLY;
else
return 0;
}

name += prefix;
namelen -= prefix;

for (i = ps->nr - 1; i >= 0; i--) {
int how;
if (seen && seen[i] == MATCHED_EXACTLY)
continue;
how = match_pathspec_item(ps->items+i, prefix, name, namelen);
if (ps->recursive && ps->max_depth != -1 &&
how && how != MATCHED_FNMATCH) {
int len = ps->items[i].len;
if (name[len] == '/')
len++;
if (within_depth(name+len, namelen-len, 0, ps->max_depth))
how = MATCHED_EXACTLY;
else
how = 0;
}
if (how) {
if (retval < how)
retval = how;
if (seen && seen[i] < how)
seen[i] = how;
}
}
return retval;
}

static int no_wildcard(const char *string)
{
return string[strcspn(string, "*?[{\\")] == '\0';
Expand Down
3 changes: 3 additions & 0 deletions dir.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ struct dir_struct {
#define MATCHED_FNMATCH 2
#define MATCHED_EXACTLY 3
extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);
extern int match_pathspec_depth(const struct pathspec *pathspec,
const char *name, int namelen,
int prefix, char *seen);
extern int within_depth(const char *name, int namelen, int depth, int max_depth);

extern int fill_directory(struct dir_struct *dir, const char **pathspec);
Expand Down

0 comments on commit 61cf282

Please sign in to comment.