* [PATCH/RFC 0/3] Support ignore rule "**" using wildmatch from rsync
@ 2012-05-07 13:01 Nguyễn Thái Ngọc Duy
2012-05-07 13:01 ` [PATCH/RFC 1/3] Import " Nguyễn Thái Ngọc Duy
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-05-07 13:01 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
I've been looking for something like this. Bash 4 has a similar
feature, but it's GPL-3. rsync is also GPL-3. Luckily this feature was
availble before the license change.
I'm not sure if we should import wildmatch just to support "**". It seems
a nice and often requested feature. And the code looks more readable than
compat/fnmatch, which is good since I don't think we can cherry pick
from (gpl3) upstream.
We would need to add case folding support or convert "abc" to
"[aA][bB][cC]". Performance vs fnmatch is another question but we
could switch to wildmatch only in the presence of "**" if wildmatch
perf sucks. Even pathspec may make use of this, thanks to pathspec
magic.
I have not looked carefully at it and this series is more like a proof
of concept than a candidate for 'pu'. Any comments in favor or oppose
this?
Nguyễn Thái Ngọc Duy (3):
Import wildmatch from rsync
Integrate wildmatch to git
gitignore: support "**" with wildmatch()
Makefile | 3 +
compat/wildmatch.c | 356 ++++++++++++++++++++++++++++++++++++++++
compat/wildmatch.h | 6 +
dir.c | 20 ++-
dir.h | 1 +
t/t3070-wildmatch.sh | 27 +++
t/t3070-wildmatch/wildtest.txt | 165 +++++++++++++++++++
test-wildmatch.c | 162 ++++++++++++++++++
8 files changed, 736 insertions(+), 4 deletions(-)
create mode 100644 compat/wildmatch.c
create mode 100644 compat/wildmatch.h
create mode 100755 t/t3070-wildmatch.sh
create mode 100644 t/t3070-wildmatch/wildtest.txt
create mode 100644 test-wildmatch.c
--
1.7.8.36.g69ee2
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH/RFC 1/3] Import wildmatch from rsync
2012-05-07 13:01 [PATCH/RFC 0/3] Support ignore rule "**" using wildmatch from rsync Nguyễn Thái Ngọc Duy
@ 2012-05-07 13:01 ` Nguyễn Thái Ngọc Duy
2012-05-07 13:01 ` [PATCH/RFC 2/3] Integrate wildmatch to git Nguyễn Thái Ngọc Duy
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-05-07 13:01 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=UTF-8, Size: 23003 bytes --]
wildmatch is the machinery behind rsync's include/exclude pattern
rules. In general it is similar to git's ignore rules, except that
"**" matches anything including patterns
These files are imported unmodified from rsync.git commit
f92f5b166e3019db42bc7fe1aa2f1a9178cd215d when they were still in GPL-2.
rsync.git -> git.git
lib/wildmatch.[ch] compat/wildmatch.[ch]
wildtest.c test-wildmatch.c
wildtest.txt t/t3070-wildmatch/wildtest.txt
Signed-off-by: Nguyá»
n Thái Ngá»c Duy <pclouds@gmail.com>
---
compat/wildmatch.c | 368 ++++++++++++++++++++++++++++++++++++++++
compat/wildmatch.h | 6 +
t/t3070-wildmatch/wildtest.txt | 165 ++++++++++++++++++
test-wildmatch.c | 216 +++++++++++++++++++++++
4 files changed, 755 insertions(+), 0 deletions(-)
create mode 100644 compat/wildmatch.c
create mode 100644 compat/wildmatch.h
create mode 100644 t/t3070-wildmatch/wildtest.txt
create mode 100644 test-wildmatch.c
diff --git a/compat/wildmatch.c b/compat/wildmatch.c
new file mode 100644
index 0000000..f3a1731
--- /dev/null
+++ b/compat/wildmatch.c
@@ -0,0 +1,368 @@
+/*
+** Do shell-style pattern matching for ?, \, [], and * characters.
+** It is 8bit clean.
+**
+** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
+** Rich $alz is now <rsalz@bbn.com>.
+**
+** Modified by Wayne Davison to special-case '/' matching, to make '**'
+** work differently than '*', and to fix the character-class code.
+*/
+
+#include "rsync.h"
+
+/* What character marks an inverted character class? */
+#define NEGATE_CLASS '!'
+#define NEGATE_CLASS2 '^'
+
+#define FALSE 0
+#define TRUE 1
+#define ABORT_ALL -1
+#define ABORT_TO_STARSTAR -2
+
+#define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 \
+ && *(class) == *(litmatch) \
+ && strncmp((char*)class, litmatch, len) == 0)
+
+#if defined STDC_HEADERS || !defined isascii
+# define ISASCII(c) 1
+#else
+# define ISASCII(c) isascii(c)
+#endif
+
+#ifdef isblank
+# define ISBLANK(c) (ISASCII(c) && isblank(c))
+#else
+# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+
+#ifdef isgraph
+# define ISGRAPH(c) (ISASCII(c) && isgraph(c))
+#else
+# define ISGRAPH(c) (ISASCII(c) && isprint(c) && !isspace(c))
+#endif
+
+#define ISPRINT(c) (ISASCII(c) && isprint(c))
+#define ISDIGIT(c) (ISASCII(c) && isdigit(c))
+#define ISALNUM(c) (ISASCII(c) && isalnum(c))
+#define ISALPHA(c) (ISASCII(c) && isalpha(c))
+#define ISCNTRL(c) (ISASCII(c) && iscntrl(c))
+#define ISLOWER(c) (ISASCII(c) && islower(c))
+#define ISPUNCT(c) (ISASCII(c) && ispunct(c))
+#define ISSPACE(c) (ISASCII(c) && isspace(c))
+#define ISUPPER(c) (ISASCII(c) && isupper(c))
+#define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
+
+#ifdef WILD_TEST_ITERATIONS
+int wildmatch_iteration_count;
+#endif
+
+static int force_lower_case = 0;
+
+/* Match pattern "p" against the a virtually-joined string consisting
+ * of "text" and any strings in array "a". */
+static int dowild(const uchar *p, const uchar *text, const uchar*const *a)
+{
+ uchar p_ch;
+
+#ifdef WILD_TEST_ITERATIONS
+ wildmatch_iteration_count++;
+#endif
+
+ for ( ; (p_ch = *p) != '\0'; text++, p++) {
+ int matched, special;
+ uchar t_ch, prev_ch;
+ while ((t_ch = *text) == '\0') {
+ if (*a == NULL) {
+ if (p_ch != '*')
+ return ABORT_ALL;
+ break;
+ }
+ text = *a++;
+ }
+ if (force_lower_case && ISUPPER(t_ch))
+ t_ch = tolower(t_ch);
+ switch (p_ch) {
+ case '\\':
+ /* Literal match with following character. Note that the test
+ * in "default" handles the p[1] == '\0' failure case. */
+ p_ch = *++p;
+ /* FALLTHROUGH */
+ default:
+ if (t_ch != p_ch)
+ return FALSE;
+ continue;
+ case '?':
+ /* Match anything but '/'. */
+ if (t_ch == '/')
+ return FALSE;
+ continue;
+ case '*':
+ if (*++p == '*') {
+ while (*++p == '*') {}
+ special = TRUE;
+ } else
+ special = FALSE;
+ if (*p == '\0') {
+ /* Trailing "**" matches everything. Trailing "*" matches
+ * only if there are no more slash characters. */
+ if (!special) {
+ do {
+ if (strchr((char*)text, '/') != NULL)
+ return FALSE;
+ } while ((text = *a++) != NULL);
+ }
+ return TRUE;
+ }
+ while (1) {
+ if (t_ch == '\0') {
+ if ((text = *a++) == NULL)
+ break;
+ t_ch = *text;
+ continue;
+ }
+ if ((matched = dowild(p, text, a)) != FALSE) {
+ if (!special || matched != ABORT_TO_STARSTAR)
+ return matched;
+ } else if (!special && t_ch == '/')
+ return ABORT_TO_STARSTAR;
+ t_ch = *++text;
+ }
+ return ABORT_ALL;
+ case '[':
+ p_ch = *++p;
+#ifdef NEGATE_CLASS2
+ if (p_ch == NEGATE_CLASS2)
+ p_ch = NEGATE_CLASS;
+#endif
+ /* Assign literal TRUE/FALSE because of "matched" comparison. */
+ special = p_ch == NEGATE_CLASS? TRUE : FALSE;
+ if (special) {
+ /* Inverted character class. */
+ p_ch = *++p;
+ }
+ prev_ch = 0;
+ matched = FALSE;
+ do {
+ if (!p_ch)
+ return ABORT_ALL;
+ if (p_ch == '\\') {
+ p_ch = *++p;
+ if (!p_ch)
+ return ABORT_ALL;
+ if (t_ch == p_ch)
+ matched = TRUE;
+ } else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') {
+ p_ch = *++p;
+ if (p_ch == '\\') {
+ p_ch = *++p;
+ if (!p_ch)
+ return ABORT_ALL;
+ }
+ if (t_ch <= p_ch && t_ch >= prev_ch)
+ matched = TRUE;
+ p_ch = 0; /* This makes "prev_ch" get set to 0. */
+ } else if (p_ch == '[' && p[1] == ':') {
+ const uchar *s;
+ int i;
+ for (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {} /*SHARED ITERATOR*/
+ if (!p_ch)
+ return ABORT_ALL;
+ i = p - s - 1;
+ if (i < 0 || p[-1] != ':') {
+ /* Didn't find ":]", so treat like a normal set. */
+ p = s - 2;
+ p_ch = '[';
+ if (t_ch == p_ch)
+ matched = TRUE;
+ continue;
+ }
+ if (CC_EQ(s,i, "alnum")) {
+ if (ISALNUM(t_ch))
+ matched = TRUE;
+ } else if (CC_EQ(s,i, "alpha")) {
+ if (ISALPHA(t_ch))
+ matched = TRUE;
+ } else if (CC_EQ(s,i, "blank")) {
+ if (ISBLANK(t_ch))
+ matched = TRUE;
+ } else if (CC_EQ(s,i, "cntrl")) {
+ if (ISCNTRL(t_ch))
+ matched = TRUE;
+ } else if (CC_EQ(s,i, "digit")) {
+ if (ISDIGIT(t_ch))
+ matched = TRUE;
+ } else if (CC_EQ(s,i, "graph")) {
+ if (ISGRAPH(t_ch))
+ matched = TRUE;
+ } else if (CC_EQ(s,i, "lower")) {
+ if (ISLOWER(t_ch))
+ matched = TRUE;
+ } else if (CC_EQ(s,i, "print")) {
+ if (ISPRINT(t_ch))
+ matched = TRUE;
+ } else if (CC_EQ(s,i, "punct")) {
+ if (ISPUNCT(t_ch))
+ matched = TRUE;
+ } else if (CC_EQ(s,i, "space")) {
+ if (ISSPACE(t_ch))
+ matched = TRUE;
+ } else if (CC_EQ(s,i, "upper")) {
+ if (ISUPPER(t_ch))
+ matched = TRUE;
+ } else if (CC_EQ(s,i, "xdigit")) {
+ if (ISXDIGIT(t_ch))
+ matched = TRUE;
+ } else /* malformed [:class:] string */
+ return ABORT_ALL;
+ p_ch = 0; /* This makes "prev_ch" get set to 0. */
+ } else if (t_ch == p_ch)
+ matched = TRUE;
+ } while (prev_ch = p_ch, (p_ch = *++p) != ']');
+ if (matched == special || t_ch == '/')
+ return FALSE;
+ continue;
+ }
+ }
+
+ do {
+ if (*text)
+ return FALSE;
+ } while ((text = *a++) != NULL);
+
+ return TRUE;
+}
+
+/* Match literal string "s" against the a virtually-joined string consisting
+ * of "text" and any strings in array "a". */
+static int doliteral(const uchar *s, const uchar *text, const uchar*const *a)
+{
+ for ( ; *s != '\0'; text++, s++) {
+ while (*text == '\0') {
+ if ((text = *a++) == NULL)
+ return FALSE;
+ }
+ if (*text != *s)
+ return FALSE;
+ }
+
+ do {
+ if (*text)
+ return FALSE;
+ } while ((text = *a++) != NULL);
+
+ return TRUE;
+}
+
+/* Return the last "count" path elements from the concatenated string.
+ * We return a string pointer to the start of the string, and update the
+ * array pointer-pointer to point to any remaining string elements. */
+static const uchar *trailing_N_elements(const uchar*const **a_ptr, int count)
+{
+ const uchar*const *a = *a_ptr;
+ const uchar*const *first_a = a;
+
+ while (*a)
+ a++;
+
+ while (a != first_a) {
+ const uchar *s = *--a;
+ s += strlen((char*)s);
+ while (--s >= *a) {
+ if (*s == '/' && !--count) {
+ *a_ptr = a+1;
+ return s+1;
+ }
+ }
+ }
+
+ if (count == 1) {
+ *a_ptr = a+1;
+ return *a;
+ }
+
+ return NULL;
+}
+
+/* Match the "pattern" against the "text" string. */
+int wildmatch(const char *pattern, const char *text)
+{
+ static const uchar *nomore[1]; /* A NULL pointer. */
+#ifdef WILD_TEST_ITERATIONS
+ wildmatch_iteration_count = 0;
+#endif
+ return dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
+}
+
+/* Match the "pattern" against the forced-to-lower-case "text" string. */
+int iwildmatch(const char *pattern, const char *text)
+{
+ static const uchar *nomore[1]; /* A NULL pointer. */
+ int ret;
+#ifdef WILD_TEST_ITERATIONS
+ wildmatch_iteration_count = 0;
+#endif
+ force_lower_case = 1;
+ ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
+ force_lower_case = 0;
+ return ret;
+}
+
+/* Match pattern "p" against the a virtually-joined string consisting
+ * of all the pointers in array "texts" (which has a NULL pointer at the
+ * end). The int "where" can be 0 (normal matching), > 0 (match only
+ * the trailing N slash-separated filename components of "texts"), or < 0
+ * (match the "pattern" at the start or after any slash in "texts"). */
+int wildmatch_array(const char *pattern, const char*const *texts, int where)
+{
+ const uchar *p = (const uchar*)pattern;
+ const uchar*const *a = (const uchar*const*)texts;
+ const uchar *text;
+ int matched;
+
+#ifdef WILD_TEST_ITERATIONS
+ wildmatch_iteration_count = 0;
+#endif
+
+ if (where > 0)
+ text = trailing_N_elements(&a, where);
+ else
+ text = *a++;
+ if (!text)
+ return FALSE;
+
+ if ((matched = dowild(p, text, a)) != TRUE && where < 0
+ && matched != ABORT_ALL) {
+ while (1) {
+ if (*text == '\0') {
+ if ((text = (uchar*)*a++) == NULL)
+ return FALSE;
+ continue;
+ }
+ if (*text++ == '/' && (matched = dowild(p, text, a)) != FALSE
+ && matched != ABORT_TO_STARSTAR)
+ break;
+ }
+ }
+ return matched == TRUE;
+}
+
+/* Match literal string "s" against the a virtually-joined string consisting
+ * of all the pointers in array "texts" (which has a NULL pointer at the
+ * end). The int "where" can be 0 (normal matching), or > 0 (match
+ * only the trailing N slash-separated filename components of "texts"). */
+int litmatch_array(const char *string, const char*const *texts, int where)
+{
+ const uchar *s = (const uchar*)string;
+ const uchar*const *a = (const uchar* const*)texts;
+ const uchar *text;
+
+ if (where > 0)
+ text = trailing_N_elements(&a, where);
+ else
+ text = *a++;
+ if (!text)
+ return FALSE;
+
+ return doliteral(s, text, a) == TRUE;
+}
diff --git a/compat/wildmatch.h b/compat/wildmatch.h
new file mode 100644
index 0000000..e7f1a35
--- /dev/null
+++ b/compat/wildmatch.h
@@ -0,0 +1,6 @@
+/* wildmatch.h */
+
+int wildmatch(const char *pattern, const char *text);
+int iwildmatch(const char *pattern, const char *text);
+int wildmatch_array(const char *pattern, const char*const *texts, int where);
+int litmatch_array(const char *string, const char*const *texts, int where);
diff --git a/t/t3070-wildmatch/wildtest.txt b/t/t3070-wildmatch/wildtest.txt
new file mode 100644
index 0000000..42c1678
--- /dev/null
+++ b/t/t3070-wildmatch/wildtest.txt
@@ -0,0 +1,165 @@
+# Input is in the following format (all items white-space separated):
+#
+# The first two items are 1 or 0 indicating if the wildmat call is expected to
+# succeed and if fnmatch works the same way as wildmat, respectively. After
+# that is a text string for the match, and a pattern string. Strings can be
+# quoted (if desired) in either double or single quotes, as well as backticks.
+#
+# MATCH FNMATCH_SAME "text to match" 'pattern to use'
+
+# Basic wildmat features
+1 1 foo foo
+0 1 foo bar
+1 1 '' ""
+1 1 foo ???
+0 1 foo ??
+1 1 foo *
+1 1 foo f*
+0 1 foo *f
+1 1 foo *foo*
+1 1 foobar *ob*a*r*
+1 1 aaaaaaabababab *ab
+1 1 foo* foo\*
+0 1 foobar foo\*bar
+1 1 f\oo f\\oo
+1 1 ball *[al]?
+0 1 ten [ten]
+1 1 ten **[!te]
+0 1 ten **[!ten]
+1 1 ten t[a-g]n
+0 1 ten t[!a-g]n
+1 1 ton t[!a-g]n
+1 1 ton t[^a-g]n
+1 1 a]b a[]]b
+1 1 a-b a[]-]b
+1 1 a]b a[]-]b
+0 1 aab a[]-]b
+1 1 aab a[]a-]b
+1 1 ] ]
+
+# Extended slash-matching features
+0 1 foo/baz/bar foo*bar
+1 1 foo/baz/bar foo**bar
+0 1 foo/bar foo?bar
+0 1 foo/bar foo[/]bar
+0 1 foo/bar f[^eiu][^eiu][^eiu][^eiu][^eiu]r
+1 1 foo-bar f[^eiu][^eiu][^eiu][^eiu][^eiu]r
+0 1 foo **/foo
+1 1 /foo **/foo
+1 1 bar/baz/foo **/foo
+0 1 bar/baz/foo */foo
+0 0 foo/bar/baz **/bar*
+1 1 deep/foo/bar/baz **/bar/*
+0 1 deep/foo/bar/baz/ **/bar/*
+1 1 deep/foo/bar/baz/ **/bar/**
+0 1 deep/foo/bar **/bar/*
+1 1 deep/foo/bar/ **/bar/**
+1 1 foo/bar/baz **/bar**
+1 1 foo/bar/baz/x */bar/**
+0 0 deep/foo/bar/baz/x */bar/**
+1 1 deep/foo/bar/baz/x **/bar/*/*
+
+# Various additional tests
+0 1 acrt a[c-c]st
+1 1 acrt a[c-c]rt
+0 1 ] [!]-]
+1 1 a [!]-]
+0 1 '' \
+0 1 \ \
+0 1 /\ */\
+1 1 /\ */\\
+1 1 foo foo
+1 1 @foo @foo
+0 1 foo @foo
+1 1 [ab] \[ab]
+1 1 [ab] [[]ab]
+1 1 [ab] [[:]ab]
+0 1 [ab] [[::]ab]
+1 1 [ab] [[:digit]ab]
+1 1 [ab] [\[:]ab]
+1 1 ?a?b \??\?b
+1 1 abc \a\b\c
+0 1 foo ''
+1 1 foo/bar/baz/to **/t[o]
+
+# Character class tests
+1 1 a1B [[:alpha:]][[:digit:]][[:upper:]]
+0 1 a [[:digit:][:upper:][:space:]]
+1 1 A [[:digit:][:upper:][:space:]]
+1 1 1 [[:digit:][:upper:][:space:]]
+0 1 1 [[:digit:][:upper:][:spaci:]]
+1 1 ' ' [[:digit:][:upper:][:space:]]
+0 1 . [[:digit:][:upper:][:space:]]
+1 1 . [[:digit:][:punct:][:space:]]
+1 1 5 [[:xdigit:]]
+1 1 f [[:xdigit:]]
+1 1 D [[:xdigit:]]
+1 1 _ [[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]
+#1 1
[^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]
+1 1 \x7f [^[:alnum:][:alpha:][:blank:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]]
+1 1 . [^[:alnum:][:alpha:][:blank:][:cntrl:][:digit:][:lower:][:space:][:upper:][:xdigit:]]
+1 1 5 [a-c[:digit:]x-z]
+1 1 b [a-c[:digit:]x-z]
+1 1 y [a-c[:digit:]x-z]
+0 1 q [a-c[:digit:]x-z]
+
+# Additional tests, including some malformed wildmats
+1 1 ] [\\-^]
+0 1 [ [\\-^]
+1 1 - [\-_]
+1 1 ] [\]]
+0 1 \] [\]]
+0 1 \ [\]]
+0 1 ab a[]b
+0 1 a[]b a[]b
+0 1 ab[ ab[
+0 1 ab [!
+0 1 ab [-
+1 1 - [-]
+0 1 - [a-
+0 1 - [!a-
+1 1 - [--A]
+1 1 5 [--A]
+1 1 ' ' '[ --]'
+1 1 $ '[ --]'
+1 1 - '[ --]'
+0 1 0 '[ --]'
+1 1 - [---]
+1 1 - [------]
+0 1 j [a-e-n]
+1 1 - [a-e-n]
+1 1 a [!------]
+0 1 [ []-a]
+1 1 ^ []-a]
+0 1 ^ [!]-a]
+1 1 [ [!]-a]
+1 1 ^ [a^bc]
+1 1 -b] [a-]b]
+0 1 \ [\]
+1 1 \ [\\]
+0 1 \ [!\\]
+1 1 G [A-\\]
+0 1 aaabbb b*a
+0 1 aabcaa *ba*
+1 1 , [,]
+1 1 , [\\,]
+1 1 \ [\\,]
+1 1 - [,-.]
+0 1 + [,-.]
+0 1 -.] [,-.]
+1 1 2 [\1-\3]
+1 1 3 [\1-\3]
+0 1 4 [\1-\3]
+1 1 \ [[-\]]
+1 1 [ [[-\]]
+1 1 ] [[-\]]
+0 1 - [[-\]]
+
+# Test recursion and the abort code (use "wildtest -i" to see iteration counts)
+1 1 -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1 -*-*-*-*-*-*-12-*-*-*-m-*-*-*
+0 1 -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1 -*-*-*-*-*-*-12-*-*-*-m-*-*-*
+0 1 -adobe-courier-bold-o-normal--12-120-75-75-/-70-iso8859-1 -*-*-*-*-*-*-12-*-*-*-m-*-*-*
+1 1 /adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1 /*/*/*/*/*/*/12/*/*/*/m/*/*/*
+0 1 /adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1 /*/*/*/*/*/*/12/*/*/*/m/*/*/*
+1 1 abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt **/*a*b*g*n*t
+0 1 abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz **/*a*b*g*n*t
diff --git a/test-wildmatch.c b/test-wildmatch.c
new file mode 100644
index 0000000..3456bac
--- /dev/null
+++ b/test-wildmatch.c
@@ -0,0 +1,216 @@
+/*
+ * Test suite for the wildmatch code.
+ *
+ * Copyright (C) 2003-2007 Wayne Davison
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/*#define COMPARE_WITH_FNMATCH*/
+
+#define WILD_TEST_ITERATIONS
+#include "lib/wildmatch.c"
+
+#include <popt.h>
+
+#ifdef COMPARE_WITH_FNMATCH
+#include <fnmatch.h>
+
+int fnmatch_errors = 0;
+#endif
+
+int wildmatch_errors = 0;
+
+typedef char bool;
+
+int output_iterations = 0;
+int explode_mod = 0;
+int empties_mod = 0;
+int empty_at_start = 0;
+int empty_at_end = 0;
+
+static struct poptOption long_options[] = {
+ /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+ {"iterations", 'i', POPT_ARG_NONE, &output_iterations, 0, 0, 0},
+ {"empties", 'e', POPT_ARG_STRING, 0, 'e', 0, 0},
+ {"explode", 'x', POPT_ARG_INT, &explode_mod, 0, 0, 0},
+ {0,0,0,0, 0, 0, 0}
+};
+
+/* match just at the start of string (anchored tests) */
+static void
+run_test(int line, bool matches, bool same_as_fnmatch,
+ const char *text, const char *pattern)
+{
+ bool matched;
+#ifdef COMPARE_WITH_FNMATCH
+ bool fn_matched;
+ int flags = strstr(pattern, "**")? 0 : FNM_PATHNAME;
+#else
+ same_as_fnmatch = 0; /* Get rid of unused-variable compiler warning. */
+#endif
+
+ if (explode_mod) {
+ char buf[MAXPATHLEN*2], *texts[MAXPATHLEN];
+ int pos = 0, cnt = 0, ndx = 0, len = strlen(text);
+
+ if (empty_at_start)
+ texts[ndx++] = "";
+ /* An empty string must turn into at least one empty array item. */
+ while (1) {
+ texts[ndx] = buf + ndx * (explode_mod + 1);
+ strlcpy(texts[ndx++], text + pos, explode_mod + 1);
+ if (pos + explode_mod >= len)
+ break;
+ pos += explode_mod;
+ if (!(++cnt % empties_mod))
+ texts[ndx++] = "";
+ }
+ if (empty_at_end)
+ texts[ndx++] = "";
+ texts[ndx] = NULL;
+ matched = wildmatch_array(pattern, (const char**)texts, 0);
+ } else
+ matched = wildmatch(pattern, text);
+#ifdef COMPARE_WITH_FNMATCH
+ fn_matched = !fnmatch(pattern, text, flags);
+#endif
+ if (matched != matches) {
+ printf("wildmatch failure on line %d:\n %s\n %s\n expected %s match\n",
+ line, text, pattern, matches? "a" : "NO");
+ wildmatch_errors++;
+ }
+#ifdef COMPARE_WITH_FNMATCH
+ if (fn_matched != (matches ^ !same_as_fnmatch)) {
+ printf("fnmatch disagreement on line %d:\n %s\n %s\n expected %s match\n",
+ line, text, pattern, matches ^ !same_as_fnmatch? "a" : "NO");
+ fnmatch_errors++;
+ }
+#endif
+ if (output_iterations) {
+ printf("%d: \"%s\" iterations = %d\n", line, pattern,
+ wildmatch_iteration_count);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ char buf[2048], *s, *string[2], *end[2];
+ const char *arg;
+ FILE *fp;
+ int opt, line, i, flag[2];
+ poptContext pc = poptGetContext("wildtest", argc, (const char**)argv,
+ long_options, 0);
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'e':
+ arg = poptGetOptArg(pc);
+ empties_mod = atoi(arg);
+ if (strchr(arg, 's'))
+ empty_at_start = 1;
+ if (strchr(arg, 'e'))
+ empty_at_end = 1;
+ if (!explode_mod)
+ explode_mod = 1024;
+ break;
+ default:
+ fprintf(stderr, "%s: %s\n",
+ poptBadOption(pc, POPT_BADOPTION_NOALIAS),
+ poptStrerror(opt));
+ exit(1);
+ }
+ }
+
+ if (explode_mod && !empties_mod)
+ empties_mod = 1024;
+
+ argv = (char**)poptGetArgs(pc);
+ if (!argv || argv[1]) {
+ fprintf(stderr, "Usage: wildtest [OPTIONS] TESTFILE\n");
+ exit(1);
+ }
+
+ if ((fp = fopen(*argv, "r")) == NULL) {
+ fprintf(stderr, "Unable to open %s\n", *argv);
+ exit(1);
+ }
+
+ line = 0;
+ while (fgets(buf, sizeof buf, fp)) {
+ line++;
+ if (*buf == '#' || *buf == '\n')
+ continue;
+ for (s = buf, i = 0; i <= 1; i++) {
+ if (*s == '1')
+ flag[i] = 1;
+ else if (*s == '0')
+ flag[i] = 0;
+ else
+ flag[i] = -1;
+ if (*++s != ' ' && *s != '\t')
+ flag[i] = -1;
+ if (flag[i] < 0) {
+ fprintf(stderr, "Invalid flag syntax on line %d of %s:\n%s",
+ line, *argv, buf);
+ exit(1);
+ }
+ while (*++s == ' ' || *s == '\t') {}
+ }
+ for (i = 0; i <= 1; i++) {
+ if (*s == '\'' || *s == '"' || *s == '`') {
+ char quote = *s++;
+ string[i] = s;
+ while (*s && *s != quote) s++;
+ if (!*s) {
+ fprintf(stderr, "Unmatched quote on line %d of %s:\n%s",
+ line, *argv, buf);
+ exit(1);
+ }
+ end[i] = s;
+ }
+ else {
+ if (!*s || *s == '\n') {
+ fprintf(stderr, "Not enough strings on line %d of %s:\n%s",
+ line, *argv, buf);
+ exit(1);
+ }
+ string[i] = s;
+ while (*++s && *s != ' ' && *s != '\t' && *s != '\n') {}
+ end[i] = s;
+ }
+ while (*++s == ' ' || *s == '\t') {}
+ }
+ *end[0] = *end[1] = '\0';
+ run_test(line, flag[0], flag[1], string[0], string[1]);
+ }
+
+ if (!wildmatch_errors)
+ fputs("No", stdout);
+ else
+ printf("%d", wildmatch_errors);
+ printf(" wildmatch error%s found.\n", wildmatch_errors == 1? "" : "s");
+
+#ifdef COMPARE_WITH_FNMATCH
+ if (!fnmatch_errors)
+ fputs("No", stdout);
+ else
+ printf("%d", fnmatch_errors);
+ printf(" fnmatch error%s found.\n", fnmatch_errors == 1? "" : "s");
+
+#endif
+
+ return 0;
+}
--
1.7.8.36.g69ee2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH/RFC 2/3] Integrate wildmatch to git
2012-05-07 13:01 [PATCH/RFC 0/3] Support ignore rule "**" using wildmatch from rsync Nguyễn Thái Ngọc Duy
2012-05-07 13:01 ` [PATCH/RFC 1/3] Import " Nguyễn Thái Ngọc Duy
@ 2012-05-07 13:01 ` Nguyễn Thái Ngọc Duy
2012-05-07 13:01 ` [PATCH/RFC 3/3] gitignore: support "**" with wildmatch() Nguyễn Thái Ngọc Duy
2012-05-07 19:05 ` [PATCH/RFC 0/3] Support ignore rule "**" using wildmatch from rsync Junio C Hamano
3 siblings, 0 replies; 5+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-05-07 13:01 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
- Make wildmatch.c part of libgit.a
- Rewrite test-wildmatch.c to follow git coding style (i.e. no
catching up with mainstream since it has turned GPL-3 anyway)
- Put wildtest.txt into a real test case
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Makefile | 3 +
compat/wildmatch.c | 26 +---
t/t3070-wildmatch.sh | 27 +++++
test-wildmatch.c | 314 +++++++++++++++++++++-----------------------------
4 files changed, 167 insertions(+), 203 deletions(-)
create mode 100755 t/t3070-wildmatch.sh
diff --git a/Makefile b/Makefile
index 2fa7211..b82f8b6 100644
--- a/Makefile
+++ b/Makefile
@@ -497,6 +497,7 @@ TEST_PROGRAMS_NEED_X += test-sha1
TEST_PROGRAMS_NEED_X += test-sigchain
TEST_PROGRAMS_NEED_X += test-subprocess
TEST_PROGRAMS_NEED_X += test-svn-fe
+TEST_PROGRAMS_NEED_X += test-wildmatch
TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
@@ -598,6 +599,7 @@ LIB_H += compat/cygwin.h
LIB_H += compat/mingw.h
LIB_H += compat/obstack.h
LIB_H += compat/terminal.h
+LIB_H += compat/wildmatch.h
LIB_H += compat/win32/dirent.h
LIB_H += compat/win32/poll.h
LIB_H += compat/win32/pthread.h
@@ -693,6 +695,7 @@ LIB_OBJS += combine-diff.o
LIB_OBJS += commit.o
LIB_OBJS += compat/obstack.o
LIB_OBJS += compat/terminal.o
+LIB_OBJS += compat/wildmatch.o
LIB_OBJS += config.o
LIB_OBJS += connect.o
LIB_OBJS += connected.o
diff --git a/compat/wildmatch.c b/compat/wildmatch.c
index f3a1731..791b9ef 100644
--- a/compat/wildmatch.c
+++ b/compat/wildmatch.c
@@ -9,7 +9,13 @@
** work differently than '*', and to fix the character-class code.
*/
-#include "rsync.h"
+#include <stddef.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "wildmatch.h"
+
+typedef unsigned char uchar;
/* What character marks an inverted character class? */
#define NEGATE_CLASS '!'
@@ -53,10 +59,6 @@
#define ISUPPER(c) (ISASCII(c) && isupper(c))
#define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
-#ifdef WILD_TEST_ITERATIONS
-int wildmatch_iteration_count;
-#endif
-
static int force_lower_case = 0;
/* Match pattern "p" against the a virtually-joined string consisting
@@ -65,10 +67,6 @@ static int dowild(const uchar *p, const uchar *text, const uchar*const *a)
{
uchar p_ch;
-#ifdef WILD_TEST_ITERATIONS
- wildmatch_iteration_count++;
-#endif
-
for ( ; (p_ch = *p) != '\0'; text++, p++) {
int matched, special;
uchar t_ch, prev_ch;
@@ -288,9 +286,6 @@ static const uchar *trailing_N_elements(const uchar*const **a_ptr, int count)
int wildmatch(const char *pattern, const char *text)
{
static const uchar *nomore[1]; /* A NULL pointer. */
-#ifdef WILD_TEST_ITERATIONS
- wildmatch_iteration_count = 0;
-#endif
return dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
}
@@ -299,9 +294,6 @@ int iwildmatch(const char *pattern, const char *text)
{
static const uchar *nomore[1]; /* A NULL pointer. */
int ret;
-#ifdef WILD_TEST_ITERATIONS
- wildmatch_iteration_count = 0;
-#endif
force_lower_case = 1;
ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
force_lower_case = 0;
@@ -320,10 +312,6 @@ int wildmatch_array(const char *pattern, const char*const *texts, int where)
const uchar *text;
int matched;
-#ifdef WILD_TEST_ITERATIONS
- wildmatch_iteration_count = 0;
-#endif
-
if (where > 0)
text = trailing_N_elements(&a, where);
else
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
new file mode 100755
index 0000000..e748fc7
--- /dev/null
+++ b/t/t3070-wildmatch.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+test_description='wildmatch tests'
+
+. ./test-lib.sh
+
+test_wildmatch() {
+ test_expect_success "wildmatch $*" "
+ test-wildmatch $* ../t3070-wildmatch/wildtest.txt >actual &&
+ echo 'No wildmatch errors found.' >expected &&
+ test_cmp expected actual
+ "
+}
+
+test_wildmatch -x1
+test_wildmatch -x1 -E1
+test_wildmatch -x1 -E1 -se
+test_wildmatch -x2
+test_wildmatch -x2 -se
+test_wildmatch -x3
+test_wildmatch -x3 -E1
+test_wildmatch -x4
+test_wildmatch -x4 -E2 -e
+test_wildmatch -x5
+test_wildmatch -x5 -s
+
+test_done
diff --git a/test-wildmatch.c b/test-wildmatch.c
index 3456bac..b832dee 100644
--- a/test-wildmatch.c
+++ b/test-wildmatch.c
@@ -17,200 +17,146 @@
* 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/*#define COMPARE_WITH_FNMATCH*/
-
-#define WILD_TEST_ITERATIONS
-#include "lib/wildmatch.c"
-
-#include <popt.h>
-
-#ifdef COMPARE_WITH_FNMATCH
-#include <fnmatch.h>
-
-int fnmatch_errors = 0;
-#endif
-
-int wildmatch_errors = 0;
-
-typedef char bool;
-
-int output_iterations = 0;
-int explode_mod = 0;
-int empties_mod = 0;
-int empty_at_start = 0;
-int empty_at_end = 0;
-
-static struct poptOption long_options[] = {
- /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
- {"iterations", 'i', POPT_ARG_NONE, &output_iterations, 0, 0, 0},
- {"empties", 'e', POPT_ARG_STRING, 0, 'e', 0, 0},
- {"explode", 'x', POPT_ARG_INT, &explode_mod, 0, 0, 0},
- {0,0,0,0, 0, 0, 0}
-};
+#include "cache.h"
+#include "parse-options.h"
+#include "compat/wildmatch.h"
+
+static int compare_fnmatch;
+static int fnmatch_errors;
+static int wildmatch_errors;
+static int explode_mod;
+static int empties_mod;
+static int empty_at_start;
+static int empty_at_end;
/* match just at the start of string (anchored tests) */
-static void
-run_test(int line, bool matches, bool same_as_fnmatch,
- const char *text, const char *pattern)
+static void run_test(int line, int matches, int same_as_fnmatch,
+ const char *text, const char *pattern)
{
- bool matched;
-#ifdef COMPARE_WITH_FNMATCH
- bool fn_matched;
- int flags = strstr(pattern, "**")? 0 : FNM_PATHNAME;
-#else
- same_as_fnmatch = 0; /* Get rid of unused-variable compiler warning. */
-#endif
-
- if (explode_mod) {
- char buf[MAXPATHLEN*2], *texts[MAXPATHLEN];
- int pos = 0, cnt = 0, ndx = 0, len = strlen(text);
+ int matched;
+ int fn_matched;
+ int flags = compare_fnmatch && strstr(pattern, "**") ? 0 : FNM_PATHNAME;
+
+ if (explode_mod) {
+ char buf[PATH_MAX * 2], *texts[PATH_MAX];
+ int pos = 0, cnt = 0, ndx = 0, len = strlen(text);
+
+ if (empty_at_start)
+ texts[ndx++] = "";
+ /* An empty string must turn into at least one empty array item. */
+ while (1) {
+ texts[ndx] = buf + ndx * (explode_mod + 1);
+ strlcpy(texts[ndx++], text + pos, explode_mod + 1);
+ if (pos + explode_mod >= len)
+ break;
+ pos += explode_mod;
+ if (!(++cnt % empties_mod))
+ texts[ndx++] = "";
+ }
+ if (empty_at_end)
+ texts[ndx++] = "";
+ texts[ndx] = NULL;
+ matched = wildmatch_array(pattern, (const char**)texts, 0);
+ } else
+ matched = wildmatch(pattern, text);
+ if (compare_fnmatch)
+ fn_matched = !fnmatch(pattern, text, flags);
+
+ if (matched != matches) {
+ printf("wildmatch failure on line %d:\n %s\n %s\n expected %s match\n",
+ line, text, pattern, matches ? "a" : "NO");
+ wildmatch_errors++;
+ }
- if (empty_at_start)
- texts[ndx++] = "";
- /* An empty string must turn into at least one empty array item. */
- while (1) {
- texts[ndx] = buf + ndx * (explode_mod + 1);
- strlcpy(texts[ndx++], text + pos, explode_mod + 1);
- if (pos + explode_mod >= len)
- break;
- pos += explode_mod;
- if (!(++cnt % empties_mod))
- texts[ndx++] = "";
+ if (compare_fnmatch && fn_matched != (matches ^ !same_as_fnmatch)) {
+ printf("fnmatch disagreement on line %d:\n %s\n %s\n expected %s match\n",
+ line, text, pattern, matches ^ !same_as_fnmatch ? "a" : "NO");
+ fnmatch_errors++;
}
- if (empty_at_end)
- texts[ndx++] = "";
- texts[ndx] = NULL;
- matched = wildmatch_array(pattern, (const char**)texts, 0);
- } else
- matched = wildmatch(pattern, text);
-#ifdef COMPARE_WITH_FNMATCH
- fn_matched = !fnmatch(pattern, text, flags);
-#endif
- if (matched != matches) {
- printf("wildmatch failure on line %d:\n %s\n %s\n expected %s match\n",
- line, text, pattern, matches? "a" : "NO");
- wildmatch_errors++;
- }
-#ifdef COMPARE_WITH_FNMATCH
- if (fn_matched != (matches ^ !same_as_fnmatch)) {
- printf("fnmatch disagreement on line %d:\n %s\n %s\n expected %s match\n",
- line, text, pattern, matches ^ !same_as_fnmatch? "a" : "NO");
- fnmatch_errors++;
- }
-#endif
- if (output_iterations) {
- printf("%d: \"%s\" iterations = %d\n", line, pattern,
- wildmatch_iteration_count);
- }
}
-int
-main(int argc, char **argv)
+int main(int argc, const char **argv)
{
- char buf[2048], *s, *string[2], *end[2];
- const char *arg;
- FILE *fp;
- int opt, line, i, flag[2];
- poptContext pc = poptGetContext("wildtest", argc, (const char**)argv,
- long_options, 0);
-
- while ((opt = poptGetNextOpt(pc)) != -1) {
- switch (opt) {
- case 'e':
- arg = poptGetOptArg(pc);
- empties_mod = atoi(arg);
- if (strchr(arg, 's'))
- empty_at_start = 1;
- if (strchr(arg, 'e'))
- empty_at_end = 1;
- if (!explode_mod)
- explode_mod = 1024;
- break;
- default:
- fprintf(stderr, "%s: %s\n",
- poptBadOption(pc, POPT_BADOPTION_NOALIAS),
- poptStrerror(opt));
- exit(1);
- }
- }
-
- if (explode_mod && !empties_mod)
- empties_mod = 1024;
-
- argv = (char**)poptGetArgs(pc);
- if (!argv || argv[1]) {
- fprintf(stderr, "Usage: wildtest [OPTIONS] TESTFILE\n");
- exit(1);
- }
-
- if ((fp = fopen(*argv, "r")) == NULL) {
- fprintf(stderr, "Unable to open %s\n", *argv);
- exit(1);
- }
-
- line = 0;
- while (fgets(buf, sizeof buf, fp)) {
- line++;
- if (*buf == '#' || *buf == '\n')
- continue;
- for (s = buf, i = 0; i <= 1; i++) {
- if (*s == '1')
- flag[i] = 1;
- else if (*s == '0')
- flag[i] = 0;
- else
- flag[i] = -1;
- if (*++s != ' ' && *s != '\t')
- flag[i] = -1;
- if (flag[i] < 0) {
- fprintf(stderr, "Invalid flag syntax on line %d of %s:\n%s",
- line, *argv, buf);
- exit(1);
- }
- while (*++s == ' ' || *s == '\t') {}
- }
- for (i = 0; i <= 1; i++) {
- if (*s == '\'' || *s == '"' || *s == '`') {
- char quote = *s++;
- string[i] = s;
- while (*s && *s != quote) s++;
- if (!*s) {
- fprintf(stderr, "Unmatched quote on line %d of %s:\n%s",
- line, *argv, buf);
- exit(1);
+ char buf[2048];
+ FILE *fp;
+ int line;
+ const struct option opts[] = {
+ OPT_INTEGER('E', "empties", &empties_mod, ""),
+ OPT_INTEGER('x', "explode", &explode_mod, "explode mode"),
+ OPT_BOOL('s', NULL, &empty_at_start, ""),
+ OPT_BOOL('e', NULL, &empty_at_end, ""),
+ OPT_BOOL(0, "fnmatch", &compare_fnmatch, "compare with fnmatch()"),
+ OPT_END(),
+ };
+
+ argc = parse_options(argc, argv, NULL, opts, NULL, 0);
+ if (argc != 1)
+ die("unknown option");
+
+ if (explode_mod && !empties_mod)
+ empties_mod = 1024;
+
+ if ((fp = fopen(*argv, "r")) == NULL)
+ die_errno("Unable to open %s\n", *argv);
+
+ line = 0;
+ while (fgets(buf, sizeof buf, fp)) {
+ char *s, *string[2], *end[2];
+ int i, flag[2];
+
+ line++;
+ if (*buf == '#' || *buf == '\n')
+ continue;
+ for (s = buf, i = 0; i <= 1; i++) {
+ if (*s == '1')
+ flag[i] = 1;
+ else if (*s == '0')
+ flag[i] = 0;
+ else
+ flag[i] = -1;
+ if (*++s != ' ' && *s != '\t')
+ flag[i] = -1;
+ if (flag[i] < 0)
+ die("Invalid flag syntax on line %d of %s:\n%s",
+ line, *argv, buf);
+ while (*++s == ' ' || *s == '\t') {}
}
- end[i] = s;
- }
- else {
- if (!*s || *s == '\n') {
- fprintf(stderr, "Not enough strings on line %d of %s:\n%s",
- line, *argv, buf);
- exit(1);
+ for (i = 0; i <= 1; i++) {
+ if (*s == '\'' || *s == '"' || *s == '`') {
+ char quote = *s++;
+ string[i] = s;
+ while (*s && *s != quote) s++;
+ if (!*s)
+ die("Unmatched quote on line %d of %s:\n%s",
+ line, *argv, buf);
+ end[i] = s;
+ }
+ else {
+ if (!*s || *s == '\n')
+ die("Not enough strings on line %d of %s:\n%s",
+ line, *argv, buf);
+ string[i] = s;
+ while (*++s && *s != ' ' && *s != '\t' && *s != '\n') {}
+ end[i] = s;
+ }
+ while (*++s == ' ' || *s == '\t') {}
}
- string[i] = s;
- while (*++s && *s != ' ' && *s != '\t' && *s != '\n') {}
- end[i] = s;
- }
- while (*++s == ' ' || *s == '\t') {}
+ *end[0] = *end[1] = '\0';
+ run_test(line, flag[0], flag[1], string[0], string[1]);
}
- *end[0] = *end[1] = '\0';
- run_test(line, flag[0], flag[1], string[0], string[1]);
- }
-
- if (!wildmatch_errors)
- fputs("No", stdout);
- else
- printf("%d", wildmatch_errors);
- printf(" wildmatch error%s found.\n", wildmatch_errors == 1? "" : "s");
-
-#ifdef COMPARE_WITH_FNMATCH
- if (!fnmatch_errors)
- fputs("No", stdout);
- else
- printf("%d", fnmatch_errors);
- printf(" fnmatch error%s found.\n", fnmatch_errors == 1? "" : "s");
-#endif
-
- return 0;
+ if (!wildmatch_errors)
+ fputs("No", stdout);
+ else
+ printf("%d", wildmatch_errors);
+ printf(" wildmatch error%s found.\n", wildmatch_errors == 1 ? "" : "s");
+
+ if (compare_fnmatch) {
+ if (!fnmatch_errors)
+ fputs("No", stdout);
+ else
+ printf("%d", fnmatch_errors);
+ printf(" fnmatch error%s found.\n", fnmatch_errors == 1 ? "" : "s");
+ }
+ return 0;
}
--
1.7.8.36.g69ee2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH/RFC 3/3] gitignore: support "**" with wildmatch()
2012-05-07 13:01 [PATCH/RFC 0/3] Support ignore rule "**" using wildmatch from rsync Nguyễn Thái Ngọc Duy
2012-05-07 13:01 ` [PATCH/RFC 1/3] Import " Nguyễn Thái Ngọc Duy
2012-05-07 13:01 ` [PATCH/RFC 2/3] Integrate wildmatch to git Nguyễn Thái Ngọc Duy
@ 2012-05-07 13:01 ` Nguyễn Thái Ngọc Duy
2012-05-07 19:05 ` [PATCH/RFC 0/3] Support ignore rule "**" using wildmatch from rsync Junio C Hamano
3 siblings, 0 replies; 5+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-05-07 13:01 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
dir.c | 20 ++++++++++++++++----
dir.h | 1 +
2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/dir.c b/dir.c
index e98760c..75140f6 100644
--- a/dir.c
+++ b/dir.c
@@ -8,6 +8,7 @@
#include "cache.h"
#include "dir.h"
#include "refs.h"
+#include "compat/wildmatch.h"
struct path_simplify {
int len;
@@ -335,6 +336,11 @@ void add_exclude(const char *string, const char *base,
x->flags |= EXC_FLAG_NODIR;
if (no_wildcard(string))
x->flags |= EXC_FLAG_NOWILDCARD;
+ else if (strstr(string, "**")) {
+ if (ignore_case)
+ warning(_("core.ignorecase is ignored in '%s' because of \"**\""), string);
+ x->flags |= EXC_FLAG_WILDMATCH;
+ }
if (*string == '*' && no_wildcard(string+1))
x->flags |= EXC_FLAG_ENDSWITH;
ALLOC_GROW(which->excludes, which->nr + 1, which->alloc);
@@ -549,11 +555,17 @@ int excluded_from_list(const char *pathname,
if (x->flags & EXC_FLAG_NOWILDCARD) {
if (!strcmp_icase(exclude, pathname + baselen))
return to_exclude;
- } else {
- if (fnmatch_icase(exclude, pathname+baselen,
- FNM_PATHNAME) == 0)
- return to_exclude;
+ continue;
+ }
+
+ if (x->flags & EXC_FLAG_WILDMATCH) {
+ if (wildmatch(exclude, pathname + baselen))
+ return to_exclude;
+ continue;
}
+ if (fnmatch_icase(exclude, pathname + baselen,
+ FNM_PATHNAME) == 0)
+ return to_exclude;
}
}
}
diff --git a/dir.h b/dir.h
index 58b6fc7..794f412 100644
--- a/dir.h
+++ b/dir.h
@@ -10,6 +10,7 @@ struct dir_entry {
#define EXC_FLAG_NOWILDCARD 2
#define EXC_FLAG_ENDSWITH 4
#define EXC_FLAG_MUSTBEDIR 8
+#define EXC_FLAG_WILDMATCH 16
struct exclude_list {
int nr;
--
1.7.8.36.g69ee2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH/RFC 0/3] Support ignore rule "**" using wildmatch from rsync
2012-05-07 13:01 [PATCH/RFC 0/3] Support ignore rule "**" using wildmatch from rsync Nguyễn Thái Ngọc Duy
` (2 preceding siblings ...)
2012-05-07 13:01 ` [PATCH/RFC 3/3] gitignore: support "**" with wildmatch() Nguyễn Thái Ngọc Duy
@ 2012-05-07 19:05 ` Junio C Hamano
3 siblings, 0 replies; 5+ messages in thread
From: Junio C Hamano @ 2012-05-07 19:05 UTC (permalink / raw)
To: Nguyễn Thái Ngọc Duy; +Cc: git
I skimmed the series and I think it would be a good change in the longer
term, but I suspect we probably have an unfinished business on the core
side that sometimes uses pathspec->raw field and assume that they only
need to do the leading-path match, which needs to be fixed first before
changes like this can be sanely added.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-05-07 19:05 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-07 13:01 [PATCH/RFC 0/3] Support ignore rule "**" using wildmatch from rsync Nguyễn Thái Ngọc Duy
2012-05-07 13:01 ` [PATCH/RFC 1/3] Import " Nguyễn Thái Ngọc Duy
2012-05-07 13:01 ` [PATCH/RFC 2/3] Integrate wildmatch to git Nguyễn Thái Ngọc Duy
2012-05-07 13:01 ` [PATCH/RFC 3/3] gitignore: support "**" with wildmatch() Nguyễn Thái Ngọc Duy
2012-05-07 19:05 ` [PATCH/RFC 0/3] Support ignore rule "**" using wildmatch from rsync Junio C Hamano
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).