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;