{"thread":{"id":"32470","subject":"[PATCH v2 0/9] fnmatch replacement step 1","startedAt":"2012-12-28T04:10:45Z","lastAt":"2012-12-28T04:10:54Z","messageCount":10,"participants":["Nguyễn Thái Ngọc Duy"],"isPatch":true,"patchVersion":2,"patchTotal":9},"messages":[{"id":"205571","messageId":"1356667854-8686-1-git-send-email-pclouds@gmail.com","threadId":"32470","inReplyTo":null,"subject":"[PATCH v2 0/9] fnmatch replacement step 1","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-12-28T04:10:45Z","receivedAt":"2012-12-28T04:10:45Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"v2 has no big changes:\n\n - 'special' variable in dowild() is removed in favor of two\n   new, better named ones\n - fix TRUE/FALSE in comments as well as code in the rename patch\n - some tests for \"*/\" and \"*<literal>\" optimizations\n - USE_WILDMATCH patch is moved to the end of the series\n\nNguyễn Thái Ngọc Duy (9):\n  compat/fnmatch: respect NO_FNMATCH* even on glibc\n  wildmatch: replace variable 'special' with better named ones\n  wildmatch: rename constants and update prototype\n  wildmatch: make dowild() take arbitrary flags\n  wildmatch: support \"no FNM_PATHNAME\" mode\n  test-wildmatch: add \"perf\" command to compare wildmatch and fnmatch\n  wildmatch: make a special case for \"*/\" with FNM_PATHNAME\n  wildmatch: advance faster in <asterisk> + <literal> patterns\n  Makefile: add USE_WILDMATCH to use wildmatch as fnmatch\n\n Makefile                 |   6 ++\n compat/fnmatch/fnmatch.c |   3 +-\n dir.c                    |   3 +-\n git-compat-util.h        |  13 +++++\n t/t3070-wildmatch.sh     |  41 +++++++++++++\n test-wildmatch.c         |  82 +++++++++++++++++++++++++-\n wildmatch.c              | 147 +++++++++++++++++++++++++++++------------------\n wildmatch.h              |  23 +++++---\n 8 files changed, 251 insertions(+), 67 deletions(-)\n\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"205572","messageId":"1356667854-8686-2-git-send-email-pclouds@gmail.com","threadId":"32470","inReplyTo":"1356667854-8686-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 1/9] compat/fnmatch: respect NO_FNMATCH* even on glibc","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-12-28T04:10:46Z","receivedAt":"2012-12-28T04:10:46Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n compat/fnmatch/fnmatch.c | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c\nindex 9473aed..6f7387d 100644\n--- a/compat/fnmatch/fnmatch.c\n+++ b/compat/fnmatch/fnmatch.c\n@@ -55,7 +55,8 @@\n    program understand `configure --with-gnu-libc' and omit the object files,\n    it is simpler to just do this in the source for each such file.  */\n \n-#if defined _LIBC || !defined __GNU_LIBRARY__\n+#if defined NO_FNMATCH || defined NO_FNMATCH_CASEFOLD || \\\n+    defined _LIBC || !defined __GNU_LIBRARY__\n \n \n # if defined STDC_HEADERS || !defined isascii\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"205573","messageId":"1356667854-8686-3-git-send-email-pclouds@gmail.com","threadId":"32470","inReplyTo":"1356667854-8686-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 2/9] wildmatch: replace variable 'special' with better named ones","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-12-28T04:10:47Z","receivedAt":"2012-12-28T04:10:47Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"'special' is too generic and is used for two different purposes.\nReplace it with 'match_slash' to indicate \"**\" pattern and 'negated'\nfor \"[!...]\" and \"[^...]\".\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n wildmatch.c | 18 +++++++++---------\n 1 file changed, 9 insertions(+), 9 deletions(-)\n\ndiff --git a/wildmatch.c b/wildmatch.c\nindex 3972e26..8a58ad4 100644\n--- a/wildmatch.c\n+++ b/wildmatch.c\n@@ -60,7 +60,7 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)\n \tuchar p_ch;\n \n \tfor ( ; (p_ch = *p) != '\\0'; text++, p++) {\n-\t\tint matched, special;\n+\t\tint matched, match_slash, negated;\n \t\tuchar t_ch, prev_ch;\n \t\tif ((t_ch = *text) == '\\0' && p_ch != '*')\n \t\t\treturn ABORT_ALL;\n@@ -102,15 +102,15 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)\n \t\t\t\t\tif (p[0] == '/' &&\n \t\t\t\t\t    dowild(p + 1, text, force_lower_case) == MATCH)\n \t\t\t\t\t\treturn MATCH;\n-\t\t\t\t\tspecial = TRUE;\n+\t\t\t\t\tmatch_slash = TRUE;\n \t\t\t\t} else\n \t\t\t\t\treturn ABORT_MALFORMED;\n \t\t\t} else\n-\t\t\t\tspecial = FALSE;\n+\t\t\t\tmatch_slash = FALSE;\n \t\t\tif (*p == '\\0') {\n \t\t\t\t/* Trailing \"**\" matches everything.  Trailing \"*\" matches\n \t\t\t\t * only if there are no more slash characters. */\n-\t\t\t\tif (!special) {\n+\t\t\t\tif (!match_slash) {\n \t\t\t\t\tif (strchr((char*)text, '/') != NULL)\n \t\t\t\t\t\treturn NOMATCH;\n \t\t\t\t}\n@@ -120,9 +120,9 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)\n \t\t\t\tif (t_ch == '\\0')\n \t\t\t\t\tbreak;\n \t\t\t\tif ((matched = dowild(p, text,  force_lower_case)) != NOMATCH) {\n-\t\t\t\t\tif (!special || matched != ABORT_TO_STARSTAR)\n+\t\t\t\t\tif (!match_slash || matched != ABORT_TO_STARSTAR)\n \t\t\t\t\t\treturn matched;\n-\t\t\t\t} else if (!special && t_ch == '/')\n+\t\t\t\t} else if (!match_slash && t_ch == '/')\n \t\t\t\t\treturn ABORT_TO_STARSTAR;\n \t\t\t\tt_ch = *++text;\n \t\t\t}\n@@ -134,8 +134,8 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)\n \t\t\t\tp_ch = NEGATE_CLASS;\n #endif\n \t\t\t/* Assign literal TRUE/FALSE because of \"matched\" comparison. */\n-\t\t\tspecial = p_ch == NEGATE_CLASS? TRUE : FALSE;\n-\t\t\tif (special) {\n+\t\t\tnegated = p_ch == NEGATE_CLASS? TRUE : FALSE;\n+\t\t\tif (negated) {\n \t\t\t\t/* Inverted character class. */\n \t\t\t\tp_ch = *++p;\n \t\t\t}\n@@ -217,7 +217,7 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)\n \t\t\t\t} else if (t_ch == p_ch)\n \t\t\t\t\tmatched = TRUE;\n \t\t\t} while (prev_ch = p_ch, (p_ch = *++p) != ']');\n-\t\t\tif (matched == special || t_ch == '/')\n+\t\t\tif (matched == negated || t_ch == '/')\n \t\t\t\treturn NOMATCH;\n \t\t\tcontinue;\n \t\t}\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"205574","messageId":"1356667854-8686-4-git-send-email-pclouds@gmail.com","threadId":"32470","inReplyTo":"1356667854-8686-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 3/9] wildmatch: rename constants and update prototype","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-12-28T04:10:48Z","receivedAt":"2012-12-28T04:10:48Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"- All exported constants now have a prefix WM_\n- Do not rely on FNM_* constants, use the WM_ counterparts\n- Remove TRUE and FALSE to follow Git's coding style\n- While at it, turn flags type from int to unsigned int\n- Add an (unused yet) argument to carry extra information\n  so that we don't have to change the prototype again later\n  when we need to pass other stuff to wildmatch\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n dir.c            |  3 +-\n test-wildmatch.c |  4 +--\n wildmatch.c      | 88 +++++++++++++++++++++++++++-----------------------------\n wildmatch.h      | 22 +++++++++-----\n 4 files changed, 62 insertions(+), 55 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex cb7328b..175a182 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -595,7 +595,8 @@ int match_pathname(const char *pathname, int pathlen,\n \t}\n \n \treturn wildmatch(pattern, name,\n-\t\t\t ignore_case ? FNM_CASEFOLD : 0) == 0;\n+\t\t\t ignore_case ? WM_CASEFOLD : 0,\n+\t\t\t NULL) == 0;\n }\n \n /* Scan the list and let the last match determine the fate.\ndiff --git a/test-wildmatch.c b/test-wildmatch.c\nindex e384c8e..4bb23b4 100644\n--- a/test-wildmatch.c\n+++ b/test-wildmatch.c\n@@ -12,9 +12,9 @@ int main(int argc, char **argv)\n \t\t\targv[i] += 3;\n \t}\n \tif (!strcmp(argv[1], \"wildmatch\"))\n-\t\treturn !!wildmatch(argv[3], argv[2], 0);\n+\t\treturn !!wildmatch(argv[3], argv[2], 0, NULL);\n \telse if (!strcmp(argv[1], \"iwildmatch\"))\n-\t\treturn !!wildmatch(argv[3], argv[2], FNM_CASEFOLD);\n+\t\treturn !!wildmatch(argv[3], argv[2], WM_CASEFOLD, NULL);\n \telse if (!strcmp(argv[1], \"fnmatch\"))\n \t\treturn !!fnmatch(argv[3], argv[2], FNM_PATHNAME);\n \telse\ndiff --git a/wildmatch.c b/wildmatch.c\nindex 8a58ad4..f9b6451 100644\n--- a/wildmatch.c\n+++ b/wildmatch.c\n@@ -18,9 +18,6 @@ typedef unsigned char uchar;\n #define NEGATE_CLASS\t'!'\n #define NEGATE_CLASS2\t'^'\n \n-#define FALSE 0\n-#define TRUE 1\n-\n #define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 \\\n \t\t\t\t    && *(class) == *(litmatch) \\\n \t\t\t\t    && strncmp((char*)class, litmatch, len) == 0)\n@@ -63,7 +60,7 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)\n \t\tint matched, match_slash, negated;\n \t\tuchar t_ch, prev_ch;\n \t\tif ((t_ch = *text) == '\\0' && p_ch != '*')\n-\t\t\treturn ABORT_ALL;\n+\t\t\treturn WM_ABORT_ALL;\n \t\tif (force_lower_case && ISUPPER(t_ch))\n \t\t\tt_ch = tolower(t_ch);\n \t\tif (force_lower_case && ISUPPER(p_ch))\n@@ -76,12 +73,12 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)\n \t\t\t/* FALLTHROUGH */\n \t\tdefault:\n \t\t\tif (t_ch != p_ch)\n-\t\t\t\treturn NOMATCH;\n+\t\t\t\treturn WM_NOMATCH;\n \t\t\tcontinue;\n \t\tcase '?':\n \t\t\t/* Match anything but '/'. */\n \t\t\tif (t_ch == '/')\n-\t\t\t\treturn NOMATCH;\n+\t\t\t\treturn WM_NOMATCH;\n \t\t\tcontinue;\n \t\tcase '*':\n \t\t\tif (*++p == '*') {\n@@ -100,135 +97,136 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)\n \t\t\t\t\t * both foo/bar and foo/a/bar.\n \t\t\t\t\t */\n \t\t\t\t\tif (p[0] == '/' &&\n-\t\t\t\t\t    dowild(p + 1, text, force_lower_case) == MATCH)\n-\t\t\t\t\t\treturn MATCH;\n-\t\t\t\t\tmatch_slash = TRUE;\n+\t\t\t\t\t    dowild(p + 1, text, force_lower_case) == WM_MATCH)\n+\t\t\t\t\t\treturn WM_MATCH;\n+\t\t\t\t\tmatch_slash = 1;\n \t\t\t\t} else\n-\t\t\t\t\treturn ABORT_MALFORMED;\n+\t\t\t\t\treturn WM_ABORT_MALFORMED;\n \t\t\t} else\n-\t\t\t\tmatch_slash = FALSE;\n+\t\t\t\tmatch_slash = 0;\n \t\t\tif (*p == '\\0') {\n \t\t\t\t/* Trailing \"**\" matches everything.  Trailing \"*\" matches\n \t\t\t\t * only if there are no more slash characters. */\n \t\t\t\tif (!match_slash) {\n \t\t\t\t\tif (strchr((char*)text, '/') != NULL)\n-\t\t\t\t\t\treturn NOMATCH;\n+\t\t\t\t\t\treturn WM_NOMATCH;\n \t\t\t\t}\n-\t\t\t\treturn MATCH;\n+\t\t\t\treturn WM_MATCH;\n \t\t\t}\n \t\t\twhile (1) {\n \t\t\t\tif (t_ch == '\\0')\n \t\t\t\t\tbreak;\n-\t\t\t\tif ((matched = dowild(p, text,  force_lower_case)) != NOMATCH) {\n-\t\t\t\t\tif (!match_slash || matched != ABORT_TO_STARSTAR)\n+\t\t\t\tif ((matched = dowild(p, text,  force_lower_case)) != WM_NOMATCH) {\n+\t\t\t\t\tif (!match_slash || matched != WM_ABORT_TO_STARSTAR)\n \t\t\t\t\t\treturn matched;\n \t\t\t\t} else if (!match_slash && t_ch == '/')\n-\t\t\t\t\treturn ABORT_TO_STARSTAR;\n+\t\t\t\t\treturn WM_ABORT_TO_STARSTAR;\n \t\t\t\tt_ch = *++text;\n \t\t\t}\n-\t\t\treturn ABORT_ALL;\n+\t\t\treturn WM_ABORT_ALL;\n \t\tcase '[':\n \t\t\tp_ch = *++p;\n #ifdef NEGATE_CLASS2\n \t\t\tif (p_ch == NEGATE_CLASS2)\n \t\t\t\tp_ch = NEGATE_CLASS;\n #endif\n-\t\t\t/* Assign literal TRUE/FALSE because of \"matched\" comparison. */\n-\t\t\tnegated = p_ch == NEGATE_CLASS? TRUE : FALSE;\n+\t\t\t/* Assign literal 1/0 because of \"matched\" comparison. */\n+\t\t\tnegated = p_ch == NEGATE_CLASS ? 1 : 0;\n \t\t\tif (negated) {\n \t\t\t\t/* Inverted character class. */\n \t\t\t\tp_ch = *++p;\n \t\t\t}\n \t\t\tprev_ch = 0;\n-\t\t\tmatched = FALSE;\n+\t\t\tmatched = 0;\n \t\t\tdo {\n \t\t\t\tif (!p_ch)\n-\t\t\t\t\treturn ABORT_ALL;\n+\t\t\t\t\treturn WM_ABORT_ALL;\n \t\t\t\tif (p_ch == '\\\\') {\n \t\t\t\t\tp_ch = *++p;\n \t\t\t\t\tif (!p_ch)\n-\t\t\t\t\t\treturn ABORT_ALL;\n+\t\t\t\t\t\treturn WM_ABORT_ALL;\n \t\t\t\t\tif (t_ch == p_ch)\n-\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\tmatched = 1;\n \t\t\t\t} else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') {\n \t\t\t\t\tp_ch = *++p;\n \t\t\t\t\tif (p_ch == '\\\\') {\n \t\t\t\t\t\tp_ch = *++p;\n \t\t\t\t\t\tif (!p_ch)\n-\t\t\t\t\t\t\treturn ABORT_ALL;\n+\t\t\t\t\t\t\treturn WM_ABORT_ALL;\n \t\t\t\t\t}\n \t\t\t\t\tif (t_ch <= p_ch && t_ch >= prev_ch)\n-\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\tp_ch = 0; /* This makes \"prev_ch\" get set to 0. */\n \t\t\t\t} else if (p_ch == '[' && p[1] == ':') {\n \t\t\t\t\tconst uchar *s;\n \t\t\t\t\tint i;\n \t\t\t\t\tfor (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {} /*SHARED ITERATOR*/\n \t\t\t\t\tif (!p_ch)\n-\t\t\t\t\t\treturn ABORT_ALL;\n+\t\t\t\t\t\treturn WM_ABORT_ALL;\n \t\t\t\t\ti = p - s - 1;\n \t\t\t\t\tif (i < 0 || p[-1] != ':') {\n \t\t\t\t\t\t/* Didn't find \":]\", so treat like a normal set. */\n \t\t\t\t\t\tp = s - 2;\n \t\t\t\t\t\tp_ch = '[';\n \t\t\t\t\t\tif (t_ch == p_ch)\n-\t\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t\tcontinue;\n \t\t\t\t\t}\n \t\t\t\t\tif (CC_EQ(s,i, \"alnum\")) {\n \t\t\t\t\t\tif (ISALNUM(t_ch))\n-\t\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t} else if (CC_EQ(s,i, \"alpha\")) {\n \t\t\t\t\t\tif (ISALPHA(t_ch))\n-\t\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t} else if (CC_EQ(s,i, \"blank\")) {\n \t\t\t\t\t\tif (ISBLANK(t_ch))\n-\t\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t} else if (CC_EQ(s,i, \"cntrl\")) {\n \t\t\t\t\t\tif (ISCNTRL(t_ch))\n-\t\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t} else if (CC_EQ(s,i, \"digit\")) {\n \t\t\t\t\t\tif (ISDIGIT(t_ch))\n-\t\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t} else if (CC_EQ(s,i, \"graph\")) {\n \t\t\t\t\t\tif (ISGRAPH(t_ch))\n-\t\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t} else if (CC_EQ(s,i, \"lower\")) {\n \t\t\t\t\t\tif (ISLOWER(t_ch))\n-\t\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t} else if (CC_EQ(s,i, \"print\")) {\n \t\t\t\t\t\tif (ISPRINT(t_ch))\n-\t\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t} else if (CC_EQ(s,i, \"punct\")) {\n \t\t\t\t\t\tif (ISPUNCT(t_ch))\n-\t\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t} else if (CC_EQ(s,i, \"space\")) {\n \t\t\t\t\t\tif (ISSPACE(t_ch))\n-\t\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t} else if (CC_EQ(s,i, \"upper\")) {\n \t\t\t\t\t\tif (ISUPPER(t_ch))\n-\t\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t} else if (CC_EQ(s,i, \"xdigit\")) {\n \t\t\t\t\t\tif (ISXDIGIT(t_ch))\n-\t\t\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\t\t\tmatched = 1;\n \t\t\t\t\t} else /* malformed [:class:] string */\n-\t\t\t\t\t\treturn ABORT_ALL;\n+\t\t\t\t\t\treturn WM_ABORT_ALL;\n \t\t\t\t\tp_ch = 0; /* This makes \"prev_ch\" get set to 0. */\n \t\t\t\t} else if (t_ch == p_ch)\n-\t\t\t\t\tmatched = TRUE;\n+\t\t\t\t\tmatched = 1;\n \t\t\t} while (prev_ch = p_ch, (p_ch = *++p) != ']');\n \t\t\tif (matched == negated || t_ch == '/')\n-\t\t\t\treturn NOMATCH;\n+\t\t\t\treturn WM_NOMATCH;\n \t\t\tcontinue;\n \t\t}\n \t}\n \n-\treturn *text ? NOMATCH : MATCH;\n+\treturn *text ? WM_NOMATCH : WM_MATCH;\n }\n \n /* Match the \"pattern\" against the \"text\" string. */\n-int wildmatch(const char *pattern, const char *text, int flags)\n+int wildmatch(const char *pattern, const char *text,\n+\t      unsigned int flags, struct wildopts *wo)\n {\n \treturn dowild((const uchar*)pattern, (const uchar*)text,\n-\t\t      flags & FNM_CASEFOLD ? 1 :0);\n+\t\t      flags & WM_CASEFOLD ? 1 :0);\n }\ndiff --git a/wildmatch.h b/wildmatch.h\nindex 984a38c..1c814fd 100644\n--- a/wildmatch.h\n+++ b/wildmatch.h\n@@ -1,9 +1,17 @@\n-/* wildmatch.h */\n+#ifndef WILDMATCH_H\n+#define WILDMATCH_H\n \n-#define ABORT_MALFORMED 2\n-#define NOMATCH 1\n-#define MATCH 0\n-#define ABORT_ALL -1\n-#define ABORT_TO_STARSTAR -2\n+#define WM_CASEFOLD 1\n \n-int wildmatch(const char *pattern, const char *text, int flags);\n+#define WM_ABORT_MALFORMED 2\n+#define WM_NOMATCH 1\n+#define WM_MATCH 0\n+#define WM_ABORT_ALL -1\n+#define WM_ABORT_TO_STARSTAR -2\n+\n+struct wildopts;\n+\n+int wildmatch(const char *pattern, const char *text,\n+\t      unsigned int flags,\n+\t      struct wildopts *wo);\n+#endif\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"205575","messageId":"1356667854-8686-5-git-send-email-pclouds@gmail.com","threadId":"32470","inReplyTo":"1356667854-8686-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 4/9] wildmatch: make dowild() take arbitrary flags","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-12-28T04:10:49Z","receivedAt":"2012-12-28T04:10:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n wildmatch.c | 13 ++++++-------\n 1 file changed, 6 insertions(+), 7 deletions(-)\n\ndiff --git a/wildmatch.c b/wildmatch.c\nindex f9b6451..68e4213 100644\n--- a/wildmatch.c\n+++ b/wildmatch.c\n@@ -52,7 +52,7 @@ typedef unsigned char uchar;\n #define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))\n \n /* Match pattern \"p\" against \"text\" */\n-static int dowild(const uchar *p, const uchar *text, int force_lower_case)\n+static int dowild(const uchar *p, const uchar *text, unsigned int flags)\n {\n \tuchar p_ch;\n \n@@ -61,9 +61,9 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)\n \t\tuchar t_ch, prev_ch;\n \t\tif ((t_ch = *text) == '\\0' && p_ch != '*')\n \t\t\treturn WM_ABORT_ALL;\n-\t\tif (force_lower_case && ISUPPER(t_ch))\n+\t\tif ((flags & WM_CASEFOLD) && ISUPPER(t_ch))\n \t\t\tt_ch = tolower(t_ch);\n-\t\tif (force_lower_case && ISUPPER(p_ch))\n+\t\tif ((flags & WM_CASEFOLD) && ISUPPER(p_ch))\n \t\t\tp_ch = tolower(p_ch);\n \t\tswitch (p_ch) {\n \t\tcase '\\\\':\n@@ -97,7 +97,7 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)\n \t\t\t\t\t * both foo/bar and foo/a/bar.\n \t\t\t\t\t */\n \t\t\t\t\tif (p[0] == '/' &&\n-\t\t\t\t\t    dowild(p + 1, text, force_lower_case) == WM_MATCH)\n+\t\t\t\t\t    dowild(p + 1, text, flags) == WM_MATCH)\n \t\t\t\t\t\treturn WM_MATCH;\n \t\t\t\t\tmatch_slash = 1;\n \t\t\t\t} else\n@@ -116,7 +116,7 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)\n \t\t\twhile (1) {\n \t\t\t\tif (t_ch == '\\0')\n \t\t\t\t\tbreak;\n-\t\t\t\tif ((matched = dowild(p, text,  force_lower_case)) != WM_NOMATCH) {\n+\t\t\t\tif ((matched = dowild(p, text, flags)) != WM_NOMATCH) {\n \t\t\t\t\tif (!match_slash || matched != WM_ABORT_TO_STARSTAR)\n \t\t\t\t\t\treturn matched;\n \t\t\t\t} else if (!match_slash && t_ch == '/')\n@@ -227,6 +227,5 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)\n int wildmatch(const char *pattern, const char *text,\n \t      unsigned int flags, struct wildopts *wo)\n {\n-\treturn dowild((const uchar*)pattern, (const uchar*)text,\n-\t\t      flags & WM_CASEFOLD ? 1 :0);\n+\treturn dowild((const uchar*)pattern, (const uchar*)text, flags);\n }\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"205576","messageId":"1356667854-8686-6-git-send-email-pclouds@gmail.com","threadId":"32470","inReplyTo":"1356667854-8686-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 5/9] wildmatch: support \"no FNM_PATHNAME\" mode","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-12-28T04:10:50Z","receivedAt":"2012-12-28T04:10:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"So far, wildmatch() has always honoured directory boundary and there\nwas no way to turn it off. Make it behave more like fnmatch() by\nrequiring all callers that want the FNM_PATHNAME behaviour to pass\nthat in the equivalent flag WM_PATHNAME. Callers that do not specify\nWM_PATHNAME will get wildcards like ? and * in their patterns matched\nagainst '/', just like not passing FNM_PATHNAME to fnmatch().\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n dir.c                |  2 +-\n t/t3070-wildmatch.sh | 27 +++++++++++++++++++++++++++\n test-wildmatch.c     |  6 ++++--\n wildmatch.c          | 13 +++++++++----\n wildmatch.h          |  1 +\n 5 files changed, 42 insertions(+), 7 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 175a182..6ef0396 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -595,7 +595,7 @@ int match_pathname(const char *pathname, int pathlen,\n \t}\n \n \treturn wildmatch(pattern, name,\n-\t\t\t ignore_case ? WM_CASEFOLD : 0,\n+\t\t\t WM_PATHNAME | (ignore_case ? WM_CASEFOLD : 0),\n \t\t\t NULL) == 0;\n }\n \ndiff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh\nindex d5bafef..dbfa903 100755\n--- a/t/t3070-wildmatch.sh\n+++ b/t/t3070-wildmatch.sh\n@@ -29,6 +29,18 @@ match() {\n     fi\n }\n \n+pathmatch() {\n+    if [ $1 = 1 ]; then\n+\ttest_expect_success \"pathmatch:    match '$2' '$3'\" \"\n+\t    test-wildmatch pathmatch '$2' '$3'\n+\t\"\n+    else\n+\ttest_expect_success \"pathmatch: no match '$2' '$3'\" \"\n+\t    ! test-wildmatch pathmatch '$2' '$3'\n+\t\"\n+    fi\n+}\n+\n # Basic wildmat features\n match 1 1 foo foo\n match 0 0 foo bar\n@@ -192,4 +204,19 @@ match 0 0 'XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1' 'XXX/*/\n match 1 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt' '**/*a*b*g*n*t'\n match 0 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz' '**/*a*b*g*n*t'\n \n+pathmatch 1 foo foo\n+pathmatch 0 foo fo\n+pathmatch 1 foo/bar foo/bar\n+pathmatch 1 foo/bar 'foo/*'\n+pathmatch 1 foo/bba/arr 'foo/*'\n+pathmatch 1 foo/bba/arr 'foo/**'\n+pathmatch 1 foo/bba/arr 'foo*'\n+pathmatch 1 foo/bba/arr 'foo**'\n+pathmatch 1 foo/bba/arr 'foo/*arr'\n+pathmatch 1 foo/bba/arr 'foo/**arr'\n+pathmatch 0 foo/bba/arr 'foo/*z'\n+pathmatch 0 foo/bba/arr 'foo/**z'\n+pathmatch 1 foo/bar 'foo?bar'\n+pathmatch 1 foo/bar 'foo[/]bar'\n+\n test_done\ndiff --git a/test-wildmatch.c b/test-wildmatch.c\nindex 4bb23b4..a5f4833 100644\n--- a/test-wildmatch.c\n+++ b/test-wildmatch.c\n@@ -12,9 +12,11 @@ int main(int argc, char **argv)\n \t\t\targv[i] += 3;\n \t}\n \tif (!strcmp(argv[1], \"wildmatch\"))\n-\t\treturn !!wildmatch(argv[3], argv[2], 0, NULL);\n+\t\treturn !!wildmatch(argv[3], argv[2], WM_PATHNAME, NULL);\n \telse if (!strcmp(argv[1], \"iwildmatch\"))\n-\t\treturn !!wildmatch(argv[3], argv[2], WM_CASEFOLD, NULL);\n+\t\treturn !!wildmatch(argv[3], argv[2], WM_PATHNAME | WM_CASEFOLD, NULL);\n+\telse if (!strcmp(argv[1], \"pathmatch\"))\n+\t\treturn !!wildmatch(argv[3], argv[2], 0, NULL);\n \telse if (!strcmp(argv[1], \"fnmatch\"))\n \t\treturn !!fnmatch(argv[3], argv[2], FNM_PATHNAME);\n \telse\ndiff --git a/wildmatch.c b/wildmatch.c\nindex 68e4213..0c8edb8 100644\n--- a/wildmatch.c\n+++ b/wildmatch.c\n@@ -77,14 +77,17 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)\n \t\t\tcontinue;\n \t\tcase '?':\n \t\t\t/* Match anything but '/'. */\n-\t\t\tif (t_ch == '/')\n+\t\t\tif ((flags & WM_PATHNAME) && t_ch == '/')\n \t\t\t\treturn WM_NOMATCH;\n \t\t\tcontinue;\n \t\tcase '*':\n \t\t\tif (*++p == '*') {\n \t\t\t\tconst uchar *prev_p = p - 2;\n \t\t\t\twhile (*++p == '*') {}\n-\t\t\t\tif ((prev_p == text || *prev_p == '/') ||\n+\t\t\t\tif (!(flags & WM_PATHNAME))\n+\t\t\t\t\t/* without WM_PATHNAME, '*' == '**' */\n+\t\t\t\t\tmatch_slash = 1;\n+\t\t\t\telse if ((prev_p == text || *prev_p == '/') ||\n \t\t\t\t    (*p == '\\0' || *p == '/' ||\n \t\t\t\t     (p[0] == '\\\\' && p[1] == '/'))) {\n \t\t\t\t\t/*\n@@ -103,7 +106,8 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)\n \t\t\t\t} else\n \t\t\t\t\treturn WM_ABORT_MALFORMED;\n \t\t\t} else\n-\t\t\t\tmatch_slash = 0;\n+\t\t\t\t/* without WM_PATHNAME, '*' == '**' */\n+\t\t\t\tmatch_slash = flags & WM_PATHNAME ? 0 : 1;\n \t\t\tif (*p == '\\0') {\n \t\t\t\t/* Trailing \"**\" matches everything.  Trailing \"*\" matches\n \t\t\t\t * only if there are no more slash characters. */\n@@ -214,7 +218,8 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)\n \t\t\t\t} else if (t_ch == p_ch)\n \t\t\t\t\tmatched = 1;\n \t\t\t} while (prev_ch = p_ch, (p_ch = *++p) != ']');\n-\t\t\tif (matched == negated || t_ch == '/')\n+\t\t\tif (matched == negated ||\n+\t\t\t    ((flags & WM_PATHNAME) && t_ch == '/'))\n \t\t\t\treturn WM_NOMATCH;\n \t\t\tcontinue;\n \t\t}\ndiff --git a/wildmatch.h b/wildmatch.h\nindex 1c814fd..4090c8f 100644\n--- a/wildmatch.h\n+++ b/wildmatch.h\n@@ -2,6 +2,7 @@\n #define WILDMATCH_H\n \n #define WM_CASEFOLD 1\n+#define WM_PATHNAME 2\n \n #define WM_ABORT_MALFORMED 2\n #define WM_NOMATCH 1\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"205577","messageId":"1356667854-8686-7-git-send-email-pclouds@gmail.com","threadId":"32470","inReplyTo":"1356667854-8686-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 6/9] test-wildmatch: add \"perf\" command to compare wildmatch and fnmatch","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-12-28T04:10:51Z","receivedAt":"2012-12-28T04:10:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"It takes a text file, a pattern, a number <n> and pathname flag. Each\nline in the text file is matched against the pattern <n> times. If\n\"pathname\" is given, FNM_PATHNAME is used.\n\ntest-wildmatch is built with -O2 and tested against glibc 2.14.1 (also\n-O2) and compat/fnmatch. The input file is linux-2.6.git file list.\n<n> is 2000. The complete command list is at the end.\n\nwildmatch is beaten in the following cases. Apparently it needs some\nimprovement in FNM_PATHNAME case:\n\nglibc, '*/*/*' with FNM_PATHNAME:\nwildmatch 8s 1559us\nfnmatch   1s 11877us or 12.65% faster\n\ncompat, '*/*/*' with FNM_PATHNAME:\nwildmatch 7s 922458us\nfnmatch   2s 905111us or 36.67% faster\n\ncompat, '*/*/*' without FNM_PATHNAME:\nwildmatch 7s 264201us\nfnmatch   2s 1897us or 27.56% faster\n\ncompat, '[a-z]*/[a-z]*/[a-z]*' with FNM_PATHNAME:\nwildmatch 8s 742827us\nfnmatch   0s 922943us or 10.56% faster\n\ncompat, '[a-z]*/[a-z]*/[a-z]*' without FNM_PATHNAME:\nwildmatch 8s 284520us\nfnmatch   0s 6936us or 0.08% faster\n\nThe rest of glibc numbers\n-------------------------\n\n'Documentation/*'\nwildmatch 1s 529479us\nfnmatch   1s 98263us or 71.81% slower\n\n'drivers/*'\nwildmatch 1s 988288us\nfnmatch   1s 192049us or 59.95% slower\n\n'Documentation/*' pathname\nwildmatch 1s 557507us\nfnmatch   1s 93696us or 70.22% slower\n\n'drivers/*' pathname\nwildmatch 2s 161626us\nfnmatch   1s 230372us or 56.92% slower\n\n'[Dd]ocu[Mn]entation/*'\nwildmatch 1s 776581us\nfnmatch   1s 471693us or 82.84% slower\n\n'[Dd]o?u[Mn]en?ati?n/*'\nwildmatch 1s 770770us\nfnmatch   1s 555727us or 87.86% slower\n\n'[Dd]o?u[Mn]en?ati?n/*' pathname\nwildmatch 1s 783507us\nfnmatch   1s 537029us or 86.18% slower\n\n'[A-Za-z][A-Za-z]??*'\nwildmatch 4s 110386us\nfnmatch   4s 926306us or 119.85% slower\n\n'[A-Za-z][A-Za-z]??'\nwildmatch 3s 918114us\nfnmatch   3s 686175us or 94.08% slower\n\n'[A-Za-z][A-Za-z]??*' pathname\nwildmatch 4s 453746us\nfnmatch   4s 955856us or 111.27% slower\n\n'[A-Za-z][A-Za-z]??' pathname\nwildmatch 3s 896646us\nfnmatch   3s 733828us or 95.82% slower\n\n'*/*/*'\nwildmatch 7s 287985us\nfnmatch   1s 74083us or 14.74% slower\n\n'[a-z]*/[a-z]*/[a-z]*' pathname\nwildmatch 8s 796659us\nfnmatch   1s 568409us or 17.83% slower\n\n'[a-z]*/[a-z]*/[a-z]*'\nwildmatch 8s 316559us\nfnmatch   3s 430652us or 41.25% slower\n\nThe rest of compat numbers\n--------------------------\n\n'Documentation/*'\nwildmatch 1s 520389us\nfnmatch   0s 62579us or 4.12% slower\n\n'drivers/*'\nwildmatch 1s 955354us\nfnmatch   0s 190109us or 9.72% slower\n\n'Documentation/*' pathname\nwildmatch 1s 561675us\nfnmatch   0s 55336us or 3.54% slower\n\n'drivers/*' pathname\nwildmatch 2s 106100us\nfnmatch   0s 219680us or 10.43% slower\n\n'[Dd]ocu[Mn]entation/*'\nwildmatch 1s 750810us\nfnmatch   0s 542721us or 31.00% slower\n\n'[Dd]o?u[Mn]en?ati?n/*'\nwildmatch 1s 724791us\nfnmatch   0s 538948us or 31.25% slower\n\n'[Dd]o?u[Mn]en?ati?n/*' pathname\nwildmatch 1s 731403us\nfnmatch   0s 537474us or 31.04% slower\n\n'[A-Za-z][A-Za-z]??*'\nwildmatch 4s 28555us\nfnmatch   1s 67297us or 26.49% slower\n\n'[A-Za-z][A-Za-z]??'\nwildmatch 3s 838279us\nfnmatch   0s 880005us or 22.93% slower\n\n'[A-Za-z][A-Za-z]??*' pathname\nwildmatch 4s 379476us\nfnmatch   1s 55643us or 24.10% slower\n\n'[A-Za-z][A-Za-z]??' pathname\nwildmatch 3s 830910us\nfnmatch   0s 849699us or 22.18% slower\n\nThe following commands are used:\n\nLANG=C ./test-wildmatch perf /tmp/filelist.txt 'Documentation/*' 2000\nLANG=C ./test-wildmatch perf /tmp/filelist.txt 'drivers/*' 2000\nLANG=C ./test-wildmatch perf /tmp/filelist.txt 'Documentation/*' 2000 pathname\nLANG=C ./test-wildmatch perf /tmp/filelist.txt 'drivers/*' 2000 pathname\nLANG=C ./test-wildmatch perf /tmp/filelist.txt '[Dd]ocu[Mn]entation/*' 2000\nLANG=C ./test-wildmatch perf /tmp/filelist.txt '[Dd]o?u[Mn]en?ati?n/*' 2000\nLANG=C ./test-wildmatch perf /tmp/filelist.txt '[Dd]o?u[Mn]en?ati?n/*' 2000 pathname\nLANG=C ./test-wildmatch perf /tmp/filelist.txt '[A-Za-z][A-Za-z]??*' 2000\nLANG=C ./test-wildmatch perf /tmp/filelist.txt '[A-Za-z][A-Za-z]??' 2000\nLANG=C ./test-wildmatch perf /tmp/filelist.txt '[A-Za-z][A-Za-z]??*' 2000 pathname\nLANG=C ./test-wildmatch perf /tmp/filelist.txt '[A-Za-z][A-Za-z]??' 2000 pathname\nLANG=C ./test-wildmatch perf /tmp/filelist.txt '*/*/*' 2000\nLANG=C ./test-wildmatch perf /tmp/filelist.txt '*/*/*' 2000 pathname\nLANG=C ./test-wildmatch perf /tmp/filelist.txt '[a-z]*/[a-z]*/[a-z]*' 2000 pathname\nLANG=C ./test-wildmatch perf /tmp/filelist.txt '[a-z]*/[a-z]*/[a-z]*' 2000\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n test-wildmatch.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 73 insertions(+)\n\ndiff --git a/test-wildmatch.c b/test-wildmatch.c\nindex a5f4833..ac86800 100644\n--- a/test-wildmatch.c\n+++ b/test-wildmatch.c\n@@ -1,9 +1,82 @@\n #include \"cache.h\"\n #include \"wildmatch.h\"\n \n+static int perf(int ac, char **av)\n+{\n+\tstruct timeval tv1, tv2;\n+\tstruct stat st;\n+\tint fd, i, n, flags1 = 0, flags2 = 0;\n+\tchar *buffer, *p;\n+\tuint32_t usec1, usec2;\n+\tconst char *lang;\n+\tconst char *file = av[0];\n+\tconst char *pattern = av[1];\n+\n+\tlang = getenv(\"LANG\");\n+\tif (lang && strcmp(lang, \"C\"))\n+\t\tdie(\"Please test it on C locale.\");\n+\n+\tif ((fd = open(file, O_RDONLY)) == -1 || fstat(fd, &st))\n+\t\tdie_errno(\"file open\");\n+\n+\tbuffer = xmalloc(st.st_size + 2);\n+\tif (read(fd, buffer, st.st_size) != st.st_size)\n+\t\tdie_errno(\"read\");\n+\n+\tbuffer[st.st_size] = '\\0';\n+\tbuffer[st.st_size + 1] = '\\0';\n+\tfor (i = 0; i < st.st_size; i++)\n+\t\tif (buffer[i] == '\\n')\n+\t\t\tbuffer[i] = '\\0';\n+\n+\tn = atoi(av[2]);\n+\tif (av[3] && !strcmp(av[3], \"pathname\")) {\n+\t\tflags1 = WM_PATHNAME;\n+\t\tflags2 = FNM_PATHNAME;\n+\t}\n+\n+\tgettimeofday(&tv1, NULL);\n+\tfor (i = 0; i < n; i++) {\n+\t\tfor (p = buffer; *p; p += strlen(p) + 1)\n+\t\t\twildmatch(pattern, p, flags1, NULL);\n+\t}\n+\tgettimeofday(&tv2, NULL);\n+\n+\tusec1 = (uint32_t)tv2.tv_sec * 1000000 + tv2.tv_usec;\n+\tusec1 -= (uint32_t)tv1.tv_sec * 1000000 + tv1.tv_usec;\n+\tprintf(\"wildmatch %ds %dus\\n\",\n+\t       (int)(usec1 / 1000000),\n+\t       (int)(usec1 % 1000000));\n+\n+\tgettimeofday(&tv1, NULL);\n+\tfor (i = 0; i < n; i++) {\n+\t\tfor (p = buffer; *p; p += strlen(p) + 1)\n+\t\t\tfnmatch(pattern, p, flags2);\n+\t}\n+\tgettimeofday(&tv2, NULL);\n+\n+\tusec2 = (uint32_t)tv2.tv_sec * 1000000 + tv2.tv_usec;\n+\tusec2 -= (uint32_t)tv1.tv_sec * 1000000 + tv1.tv_usec;\n+\tif (usec2 > usec1)\n+\t\tprintf(\"fnmatch   %ds %dus or %.2f%% slower\\n\",\n+\t\t       (int)((usec2 - usec1) / 1000000),\n+\t\t       (int)((usec2 - usec1) % 1000000),\n+\t\t       (float)(usec2 - usec1) / usec1 * 100);\n+\telse\n+\t\tprintf(\"fnmatch   %ds %dus or %.2f%% faster\\n\",\n+\t\t       (int)((usec1 - usec2) / 1000000),\n+\t\t       (int)((usec1 - usec2) % 1000000),\n+\t\t       (float)(usec1 - usec2) / usec1 * 100);\n+\treturn 0;\n+}\n+\n int main(int argc, char **argv)\n {\n \tint i;\n+\n+\tif (!strcmp(argv[1], \"perf\"))\n+\t\treturn perf(argc - 2, argv + 2);\n+\n \tfor (i = 2; i < argc; i++) {\n \t\tif (argv[i][0] == '/')\n \t\t\tdie(\"Forward slash is not allowed at the beginning of the\\n\"\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"205578","messageId":"1356667854-8686-8-git-send-email-pclouds@gmail.com","threadId":"32470","inReplyTo":"1356667854-8686-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 7/9] wildmatch: make a special case for \"*/\" with FNM_PATHNAME","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-12-28T04:10:52Z","receivedAt":"2012-12-28T04:10:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Normally we need recursion for \"*\". In this case we know that it\nmatches everything until \"/\" so we can skip the recursion.\n\nglibc, '*/*/*' on linux-2.6.git file list 2000 times\nbefore:\nwildmatch 8s 74513us\nfnmatch   1s 97042us or 13.59% faster\nafter:\nwildmatch 3s 521862us\nfnmatch   3s 488616us or 99.06% slower\n\nSame test with compat/fnmatch:\nwildmatch 8s 110763us\nfnmatch   2s 980845us or 36.75% faster\nwildmatch 3s 522156us\nfnmatch   1s 544487us or 43.85% slower\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n t/t3070-wildmatch.sh |  8 ++++++++\n wildmatch.c          | 12 ++++++++++++\n 2 files changed, 20 insertions(+)\n\ndiff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh\nindex dbfa903..4cdb13b 100755\n--- a/t/t3070-wildmatch.sh\n+++ b/t/t3070-wildmatch.sh\n@@ -203,6 +203,10 @@ match 1 1 'XXX/adobe/courier/bold/o/normal//12/120/75/75/m/70/iso8859/1' 'XXX/*/\n match 0 0 'XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1' 'XXX/*/*/*/*/*/*/12/*/*/*/m/*/*/*'\n match 1 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt' '**/*a*b*g*n*t'\n match 0 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz' '**/*a*b*g*n*t'\n+match 0 x foo '*/*/*'\n+match 0 x foo/bar '*/*/*'\n+match 1 x foo/bba/arr '*/*/*'\n+match 0 x foo/bb/aa/rr '*/*/*'\n \n pathmatch 1 foo foo\n pathmatch 0 foo fo\n@@ -218,5 +222,9 @@ pathmatch 0 foo/bba/arr 'foo/*z'\n pathmatch 0 foo/bba/arr 'foo/**z'\n pathmatch 1 foo/bar 'foo?bar'\n pathmatch 1 foo/bar 'foo[/]bar'\n+pathmatch 0 foo '*/*/*'\n+pathmatch 0 foo/bar '*/*/*'\n+pathmatch 1 foo/bba/arr '*/*/*'\n+pathmatch 1 foo/bb/aa/rr '*/*/*'\n \n test_done\ndiff --git a/wildmatch.c b/wildmatch.c\nindex 0c8edb8..f6d45d5 100644\n--- a/wildmatch.c\n+++ b/wildmatch.c\n@@ -116,6 +116,18 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)\n \t\t\t\t\t\treturn WM_NOMATCH;\n \t\t\t\t}\n \t\t\t\treturn WM_MATCH;\n+\t\t\t} else if (*p == '/' && (flags & WM_PATHNAME) && !match_slash) {\n+\t\t\t\t/*\n+\t\t\t\t * an asterisk followed by a slash\n+\t\t\t\t * with WM_PATHNAME matches the next\n+\t\t\t\t * directory\n+\t\t\t\t */\n+\t\t\t\tconst char *slash = strchr((char*)text, '/');\n+\t\t\t\tif (!slash)\n+\t\t\t\t\treturn WM_NOMATCH;\n+\t\t\t\ttext = (const uchar*)slash;\n+\t\t\t\t/* the slash is consumed by the top-level for loop */\n+\t\t\t\tbreak;\n \t\t\t}\n \t\t\twhile (1) {\n \t\t\t\tif (t_ch == '\\0')\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"205579","messageId":"1356667854-8686-9-git-send-email-pclouds@gmail.com","threadId":"32470","inReplyTo":"1356667854-8686-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 8/9] wildmatch: advance faster in <asterisk> + <literal> patterns","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-12-28T04:10:53Z","receivedAt":"2012-12-28T04:10:53Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"compat, '*/*/*' on linux-2.6.git file list 2000 times, before:\nwildmatch 7s 985049us\nfnmatch   2s 735541us or 34.26% faster\n\nand after:\nwildmatch 4s 492549us\nfnmatch   0s 888263us or 19.77% slower\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n t/t3070-wildmatch.sh |  6 ++++++\n wildmatch.c          | 21 +++++++++++++++++++++\n 2 files changed, 27 insertions(+)\n\ndiff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh\nindex 4cdb13b..dcbc8bc 100755\n--- a/t/t3070-wildmatch.sh\n+++ b/t/t3070-wildmatch.sh\n@@ -207,6 +207,9 @@ match 0 x foo '*/*/*'\n match 0 x foo/bar '*/*/*'\n match 1 x foo/bba/arr '*/*/*'\n match 0 x foo/bb/aa/rr '*/*/*'\n+match 1 x abcXdefXghi '*X*i'\n+match 0 x ab/cXd/efXg/hi '*X*i'\n+match 1 x ab/cXd/efXg/hi '*/*X*/*/*i'\n \n pathmatch 1 foo foo\n pathmatch 0 foo fo\n@@ -226,5 +229,8 @@ pathmatch 0 foo '*/*/*'\n pathmatch 0 foo/bar '*/*/*'\n pathmatch 1 foo/bba/arr '*/*/*'\n pathmatch 1 foo/bb/aa/rr '*/*/*'\n+pathmatch 1 abcXdefXghi '*X*i'\n+pathmatch 1 ab/cXd/efXg/hi '*/*X*/*/*i'\n+pathmatch 1 ab/cXd/efXg/hi '*Xg*i'\n \n test_done\ndiff --git a/wildmatch.c b/wildmatch.c\nindex f6d45d5..40eda08 100644\n--- a/wildmatch.c\n+++ b/wildmatch.c\n@@ -132,6 +132,27 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)\n \t\t\twhile (1) {\n \t\t\t\tif (t_ch == '\\0')\n \t\t\t\t\tbreak;\n+\t\t\t\t/*\n+\t\t\t\t * Try to advance faster when an asterisk is\n+\t\t\t\t * followed by a literal. We know in this case\n+\t\t\t\t * that the the string before the literal\n+\t\t\t\t * must belong to \"*\".\n+\t\t\t\t */\n+\t\t\t\tif (!is_glob_special(*p)) {\n+\t\t\t\t\tp_ch = *p;\n+\t\t\t\t\tif ((flags & WM_CASEFOLD) && ISUPPER(p_ch))\n+\t\t\t\t\t\tp_ch = tolower(p_ch);\n+\t\t\t\t\twhile ((t_ch = *text) != '\\0' &&\n+\t\t\t\t\t       (!(flags & WM_PATHNAME) || t_ch != '/')) {\n+\t\t\t\t\t\tif ((flags & WM_CASEFOLD) && ISUPPER(t_ch))\n+\t\t\t\t\t\t\tt_ch = tolower(t_ch);\n+\t\t\t\t\t\tif (t_ch == p_ch)\n+\t\t\t\t\t\t\tbreak;\n+\t\t\t\t\t\ttext++;\n+\t\t\t\t\t}\n+\t\t\t\t\tif (t_ch != p_ch)\n+\t\t\t\t\t\treturn WM_NOMATCH;\n+\t\t\t\t}\n \t\t\t\tif ((matched = dowild(p, text, flags)) != WM_NOMATCH) {\n \t\t\t\t\tif (!match_slash || matched != WM_ABORT_TO_STARSTAR)\n \t\t\t\t\t\treturn matched;\n-- \n1.8.0.rc2.23.g1fb49df\n"},{"id":"205580","messageId":"1356667854-8686-10-git-send-email-pclouds@gmail.com","threadId":"32470","inReplyTo":"1356667854-8686-1-git-send-email-pclouds@gmail.com","subject":"[PATCH v2 9/9] Makefile: add USE_WILDMATCH to use wildmatch as fnmatch","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2012-12-28T04:10:54Z","receivedAt":"2012-12-28T04:10:54Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is similar to NO_FNMATCH but it uses wildmatch instead of\ncompat/fnmatch. This is an intermediate step to let wildmatch be used\nas fnmatch replacement for wider audience before it replaces fnmatch\ncompletely and compat/fnmatch is removed.\n\nfnmatch in test-wildmatch is not impacted by this and is the only\nplace that NO_FNMATCH or NO_FNMATCH_CASEFOLD remain active when\nUSE_WILDMATCH is set.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Makefile          |  6 ++++++\n git-compat-util.h | 13 +++++++++++++\n test-wildmatch.c  |  3 +++\n 3 files changed, 22 insertions(+)\n\ndiff --git a/Makefile b/Makefile\nindex bc868d1..24e2774 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -99,6 +99,9 @@ all::\n # Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the\n # FNM_CASEFOLD GNU extension.\n #\n+# Define USE_WILDMATCH if you want to use Git's wildmatch\n+# implementation as fnmatch\n+#\n # Define NO_GECOS_IN_PWENT if you don't have pw_gecos in struct passwd\n # in the C library.\n #\n@@ -1625,6 +1628,9 @@ ifdef NO_FNMATCH_CASEFOLD\n \tCOMPAT_OBJS += compat/fnmatch/fnmatch.o\n endif\n endif\n+ifdef USE_WILDMATCH\n+\tCOMPAT_CFLAGS += -DUSE_WILDMATCH\n+endif\n ifdef NO_SETENV\n \tCOMPAT_CFLAGS += -DNO_SETENV\n \tCOMPAT_OBJS += compat/setenv.o\ndiff --git a/git-compat-util.h b/git-compat-util.h\nindex 02f48f6..b2c7638 100644\n--- a/git-compat-util.h\n+++ b/git-compat-util.h\n@@ -106,7 +106,9 @@\n #include <sys/time.h>\n #include <time.h>\n #include <signal.h>\n+#ifndef USE_WILDMATCH\n #include <fnmatch.h>\n+#endif\n #include <assert.h>\n #include <regex.h>\n #include <utime.h>\n@@ -238,6 +240,17 @@ extern char *gitbasename(char *);\n \n #include \"compat/bswap.h\"\n \n+#ifdef USE_WILDMATCH\n+#include \"wildmatch.h\"\n+#define FNM_PATHNAME WM_PATHNAME\n+#define FNM_CASEFOLD WM_CASEFOLD\n+#define FNM_NOMATCH  WM_NOMATCH\n+static inline int fnmatch(const char *pattern, const char *string, int flags)\n+{\n+\treturn wildmatch(pattern, string, flags, NULL);\n+}\n+#endif\n+\n /* General helper functions */\n extern void vreportf(const char *prefix, const char *err, va_list params);\n extern void vwritef(int fd, const char *prefix, const char *err, va_list params);\ndiff --git a/test-wildmatch.c b/test-wildmatch.c\nindex ac86800..a3e2643 100644\n--- a/test-wildmatch.c\n+++ b/test-wildmatch.c\n@@ -1,3 +1,6 @@\n+#ifdef USE_WILDMATCH\n+#undef USE_WILDMATCH  /* We need real fnmatch implementation here */\n+#endif\n #include \"cache.h\"\n #include \"wildmatch.h\"\n \n-- \n1.8.0.rc2.23.g1fb49df\n"}]}