Browse Source

match_pathspec() -- return how well the spec matched

This updates the return value from match_pathspec() so that the
caller can tell cases between exact match, leading pathname
match (i.e. file "foo/bar" matches a pathspec "foo"), or
filename glob match.  This can be used to prevent "rm dir" from
removing "dir/file" without explicitly asking for recursive
behaviour with -r flag, for example.

Signed-off-by: Junio C Hamano <junkio@cox.net>
maint
Junio C Hamano 18 years ago
parent
commit
e813d50e35
  1. 51
      dir.c
  2. 4
      dir.h

51
dir.c

@ -40,6 +40,18 @@ int common_prefix(const char **pathspec)
return prefix; return prefix;
} }


/*
* Does 'match' matches 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_one(const char *match, const char *name, int namelen) static int match_one(const char *match, const char *name, int namelen)
{ {
int matchlen; int matchlen;
@ -47,27 +59,30 @@ static int match_one(const char *match, const char *name, int namelen)
/* If the match was just the prefix, we matched */ /* If the match was just the prefix, we matched */
matchlen = strlen(match); matchlen = strlen(match);
if (!matchlen) if (!matchlen)
return 1; return MATCHED_RECURSIVELY;


/* /*
* If we don't match the matchstring exactly, * If we don't match the matchstring exactly,
* we need to match by fnmatch * we need to match by fnmatch
*/ */
if (strncmp(match, name, matchlen)) if (strncmp(match, name, matchlen))
return !fnmatch(match, name, 0); return !fnmatch(match, name, 0) ? MATCHED_FNMATCH : 0;


/* if (!name[matchlen])
* If we did match the string exactly, we still return MATCHED_EXACTLY;
* need to make sure that it happened on a path if (match[matchlen-1] == '/' || name[matchlen] == '/')
* component boundary (ie either the last character return MATCHED_RECURSIVELY;
* of the match was '/', or the next character of return 0;
* the name was '/' or the terminating NUL.
*/
return match[matchlen-1] == '/' ||
name[matchlen] == '/' ||
!name[matchlen];
} }


/*
* 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(const char **pathspec, const char *name, int namelen, int prefix, char *seen) int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen)
{ {
int retval; int retval;
@ -77,12 +92,16 @@ int match_pathspec(const char **pathspec, const char *name, int namelen, int pre
namelen -= prefix; namelen -= prefix;


for (retval = 0; (match = *pathspec++) != NULL; seen++) { for (retval = 0; (match = *pathspec++) != NULL; seen++) {
if (retval & *seen) int how;
if (retval && *seen == MATCHED_EXACTLY)
continue; continue;
match += prefix; match += prefix;
if (match_one(match, name, namelen)) { how = match_one(match, name, namelen);
retval = 1; if (how) {
*seen = 1; if (retval < how)
retval = how;
if (*seen < how)
*seen = how;
} }
} }
return retval; return retval;

4
dir.h

@ -40,6 +40,10 @@ struct dir_struct {
}; };


extern int common_prefix(const char **pathspec); extern int common_prefix(const char **pathspec);

#define MATCHED_RECURSIVELY 1
#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(const char **pathspec, const char *name, int namelen, int prefix, char *seen);


extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen); extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen);

Loading…
Cancel
Save