exclude: do strcmp as much as possible before fnmatch
this also avoids calling fnmatch() if the non-wildcard prefix is longer than basename 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
Jun 7, 2012 at 14:53 UTC
f9f6e2ce26e25661245a6faaf0b254524c1bfbd4
2 files changed
+25
-14
dir.c
+24
-13
@@ -341,8 +341,7 @@ void add_exclude(const char *string, const char *base,
341
x->flags = flags;
342
if (!strchr(string, '/'))
343
x->flags |= EXC_FLAG_NODIR;
344
- if (no_wildcard(string))
345
- x->flags |= EXC_FLAG_NOWILDCARD;
344
+ x->nowildcardlen = simple_length(string);
345
if (*string == '*' && no_wildcard(string+1))
346
x->flags |= EXC_FLAG_ENDSWITH;
347
ALLOC_GROW(which->excludes, which->nr + 1, which->alloc);
@@ -518,8 +517,9 @@ int excluded_from_list(const char *pathname,
517
518
for (i = el->nr - 1; 0 <= i; i--) {
519
struct exclude *x = el->excludes[i];
521
- const char *exclude = x->pattern;
520
+ const char *name, *exclude = x->pattern;
521
int to_exclude = x->to_exclude;
522
+ int namelen, prefix = x->nowildcardlen;
523
524
if (x->flags & EXC_FLAG_MUSTBEDIR) {
525
if (*dtype == DT_UNKNOWN)
@@ -530,7 +530,7 @@ int excluded_from_list(const char *pathname,
530
531
if (x->flags & EXC_FLAG_NODIR) {
532
/* match basename */
533
- if (x->flags & EXC_FLAG_NOWILDCARD) {
533
+ if (prefix == x->patternlen) {
534
if (!strcmp_icase(exclude, basename))
535
return to_exclude;
536
} else if (x->flags & EXC_FLAG_ENDSWITH) {
@@ -544,26 +544,37 @@ int excluded_from_list(const char *pathname,
544
continue;
545
}
546
547
-
547
/* match with FNM_PATHNAME:
548
* exclude has base (baselen long) implicitly in front of it.
549
*/
551
- if (*exclude == '/')
550
+ if (*exclude == '/') {
551
exclude++;
552
+ prefix--;
553
+ }
554
555
if (pathlen < x->baselen ||
556
(x->baselen && pathname[x->baselen-1] != '/') ||
557
strncmp_icase(pathname, x->base, x->baselen))
558
continue;
559
559
- if (x->flags & EXC_FLAG_NOWILDCARD) {
560
- if (!strcmp_icase(exclude, pathname + x->baselen))
561
- return to_exclude;
562
- } else {
563
- if (fnmatch_icase(exclude, pathname+x->baselen,
564
- FNM_PATHNAME) == 0)
565
- return to_exclude;
560
+ namelen = x->baselen ? pathlen - x->baselen : pathlen;
561
+ name = pathname + pathlen - namelen;
562
+
563
+ /* if the non-wildcard part is longer than the
564
+ remaining pathname, surely it cannot match */
565
+ if (prefix > namelen)
566
+ continue;
567
+
568
+ if (prefix) {
569
+ if (strncmp_icase(exclude, name, prefix))
570
+ continue;
571
+ exclude += prefix;
572
+ name += prefix;
573
+ namelen -= prefix;
574
}
575
+
576
+ if (!namelen || !fnmatch_icase(exclude, name, FNM_PATHNAME))
577
+ return to_exclude;
578
}
579
return -1; /* undecided */
580
}
dir.h
+1
-1
@@ -7,7 +7,6 @@ struct dir_entry {
7
};
8
9
#define EXC_FLAG_NODIR 1
10
-#define EXC_FLAG_NOWILDCARD 2
10
#define EXC_FLAG_ENDSWITH 4
11
#define EXC_FLAG_MUSTBEDIR 8
12
@@ -17,6 +16,7 @@ struct exclude_list {
16
struct exclude {
17
const char *pattern;
18
int patternlen;
19
+ int nowildcardlen;
20
const char *base;
21
int baselen;
22
int to_exclude;