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>maint
							parent
							
								
									f1a2ddbbc2
								
							
						
					
					
						commit
						61cf282045
					
				
							
								
								
									
										89
									
								
								dir.c
								
								
								
								
							
							
						
						
									
										89
									
								
								dir.c
								
								
								
								
							|  | @ -199,6 +199,95 @@ int match_pathspec(const char **pathspec, const char *name, int namelen, | ||||||
| 	return retval; | 	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) | static int no_wildcard(const char *string) | ||||||
| { | { | ||||||
| 	return string[strcspn(string, "*?[{\\")] == '\0'; | 	return string[strcspn(string, "*?[{\\")] == '\0'; | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								dir.h
								
								
								
								
							
							
						
						
									
										3
									
								
								dir.h
								
								
								
								
							|  | @ -65,6 +65,9 @@ struct dir_struct { | ||||||
| #define MATCHED_FNMATCH 2 | #define MATCHED_FNMATCH 2 | ||||||
| #define MATCHED_EXACTLY 3 | #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 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 within_depth(const char *name, int namelen, int depth, int max_depth); | ||||||
|  |  | ||||||
| extern int fill_directory(struct dir_struct *dir, const char **pathspec); | extern int fill_directory(struct dir_struct *dir, const char **pathspec); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Nguyễn Thái Ngọc Duy
						Nguyễn Thái Ngọc Duy