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>
This commit is contained in:
parent
d4ada4876d
commit
e813d50e35
51
dir.c
51
dir.c
@ -40,6 +40,18 @@ int common_prefix(const char **pathspec)
|
||||
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)
|
||||
{
|
||||
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 */
|
||||
matchlen = strlen(match);
|
||||
if (!matchlen)
|
||||
return 1;
|
||||
return MATCHED_RECURSIVELY;
|
||||
|
||||
/*
|
||||
* If we don't match the matchstring exactly,
|
||||
* we need to match by fnmatch
|
||||
*/
|
||||
if (strncmp(match, name, matchlen))
|
||||
return !fnmatch(match, name, 0);
|
||||
return !fnmatch(match, name, 0) ? MATCHED_FNMATCH : 0;
|
||||
|
||||
/*
|
||||
* If we did match the string exactly, we still
|
||||
* need to make sure that it happened on a path
|
||||
* component boundary (ie either the last character
|
||||
* of the match was '/', or the next character of
|
||||
* the name was '/' or the terminating NUL.
|
||||
*/
|
||||
return match[matchlen-1] == '/' ||
|
||||
name[matchlen] == '/' ||
|
||||
!name[matchlen];
|
||||
if (!name[matchlen])
|
||||
return MATCHED_EXACTLY;
|
||||
if (match[matchlen-1] == '/' || name[matchlen] == '/')
|
||||
return MATCHED_RECURSIVELY;
|
||||
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(const char **pathspec, const char *name, int namelen, int prefix, char *seen)
|
||||
{
|
||||
int retval;
|
||||
@ -77,12 +92,16 @@ int match_pathspec(const char **pathspec, const char *name, int namelen, int pre
|
||||
namelen -= prefix;
|
||||
|
||||
for (retval = 0; (match = *pathspec++) != NULL; seen++) {
|
||||
if (retval & *seen)
|
||||
int how;
|
||||
if (retval && *seen == MATCHED_EXACTLY)
|
||||
continue;
|
||||
match += prefix;
|
||||
if (match_one(match, name, namelen)) {
|
||||
retval = 1;
|
||||
*seen = 1;
|
||||
how = match_one(match, name, namelen);
|
||||
if (how) {
|
||||
if (retval < how)
|
||||
retval = how;
|
||||
if (*seen < how)
|
||||
*seen = how;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
|
4
dir.h
4
dir.h
@ -40,6 +40,10 @@ struct dir_struct {
|
||||
};
|
||||
|
||||
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 read_directory(struct dir_struct *, const char *path, const char *base, int baselen);
|
||||
|
Loading…
Reference in New Issue
Block a user