Skip to contentSkip to conversation

Good bye fnmatch

PATCH In review Nguyễn Thái Ngọc Duy 3 participants 9 messages Jun 15, 2016 Kbuild

lore
Share & tools
lore
#0 lore raw

cover Good bye fnmatch

Long story short, we wanted globbing wildcard "**" so I ripped wildmatch library from rsync to do it. And it opened a possibility to replace fnmatch completely, which would provide consistent behavior across platforms (native fnmatch behaves differently on many corner cases), and some performance gains. I started fnmatch replacement with 4917e1e (Makefile: promote wildmatch to be the default fnmatch implementation - 2013-05-30). This is the final step.

Nguyễn Thái Ngọc Duy (4):
Use wildmatch() directly without fnmatch() wrapper
Revert "test-wildmatch: add "perf" command to compare wildmatch and fnmatch" Stop using fnmatch (either native or compat)
Actually remove compat fnmatch source code

 Makefile                        |  22 --
 builtin/apply.c                 |   2 +-
 builtin/branch.c                |   2 +-
 builtin/describe.c              |   2 +-
 builtin/for-each-ref.c          |   2 +-
 builtin/ls-remote.c             |   2 +-
 builtin/name-rev.c              |   2 +-
 builtin/reflog.c                |   2 +-
 builtin/replace.c               |   2 +-
 builtin/show-branch.c           |   2 +-
 builtin/tag.c                   |   2 +-
 compat/fnmatch/fnmatch.c (gone) | 494 ----------------------------------------
 compat/fnmatch/fnmatch.h (gone) |  84 -------
 config.mak.uname                |  10 -
 configure.ac                    |  28 ---
 diffcore-order.c                |   2 +-
 dir.c                           |  11 +-
 git-compat-util.h               |  12 -
 refs.c                          |   2 +-
 revision.c                      |   2 +-
 t/t3070-wildmatch.sh            |  13 --
 test-wildmatch.c                |  79 -------
 22 files changed, 20 insertions(+), 759 deletions(-)
Signature · 1 line
1.8.5.2.240.g8478abd
#1 lore raw

PATCH 1/4 Use wildmatch() directly without fnmatch() wrapper

Make it clear that we don't use fnmatch() anymore.

---
 builtin/apply.c        |  2 +-
 builtin/branch.c       |  2 +-
 builtin/describe.c     |  2 +-
 builtin/for-each-ref.c |  2 +-
 builtin/ls-remote.c    |  2 +-
 builtin/name-rev.c     |  2 +-
 builtin/reflog.c       |  2 +-
 builtin/replace.c      |  2 +-
 builtin/show-branch.c  |  2 +-
 builtin/tag.c          |  2 +-
 diffcore-order.c       |  2 +-
 dir.c                  | 11 +++++++----
 refs.c                 |  2 +-
 revision.c             |  2 +-
 14 files changed, 20 insertions(+), 17 deletions(-)
builtin/apply.c +1 -1
index b0d0986..66e2eed 100644
@@ -4152,7 +4152,7 @@ static int use_patch(struct patch *p)
 	/* See if it matches any of exclude/include rule */
 	for (i = 0; i < limit_by_name.nr; i++) {
 		struct string_list_item *it = &limit_by_name.items[i];
-		if (!fnmatch(it->string, pathname, 0))
+		if (!wildmatch(it->string, pathname, 0, NULL))
 			return (it->util != NULL);
 	}
 
builtin/branch.c +1 -1
index b4d7716..652b1d2 100644
@@ -315,7 +315,7 @@ static int match_patterns(const char **pattern, const char *refname)
 	if (!*pattern)
 		return 1; /* no pattern always matches */
 	while (*pattern) {
-		if (!fnmatch(*pattern, refname, 0))
+		if (!wildmatch(*pattern, refname, 0, NULL))
 			return 1;
 		pattern++;
 	}
builtin/describe.c +1 -1
index 7db43da..848acdf 100644
@@ -150,7 +150,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
 		return 0;
 
 	/* Accept only tags that match the pattern, if given */
-	if (pattern && (!is_tag || fnmatch(pattern, path + 10, 0)))
+	if (pattern && (!is_tag || wildmatch(pattern, path + 10, 0, NULL)))
 		return 0;
 
 	/* Is it annotated? */
builtin/for-each-ref.c +1 -1
index 51798b4..3e1d5c3 100644
@@ -864,7 +864,7 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f
 			     refname[plen] == '/' ||
 			     p[plen-1] == '/'))
 				break;
-			if (!fnmatch(p, refname, FNM_PATHNAME))
+			if (!wildmatch(p, refname, WM_PATHNAME, NULL))
 				break;
 		}
 		if (!*pattern)
builtin/ls-remote.c +1 -1
index 39e5144..3e9eefb 100644
@@ -22,7 +22,7 @@ static int tail_match(const char **pattern, const char *path)
 	if (snprintf(pathbuf, sizeof(pathbuf), "/%s", path) > sizeof(pathbuf))
 		return error("insanely long ref %.*s...", 20, path);
 	while ((p = *(pattern++)) != NULL) {
-		if (!fnmatch(p, pathbuf, 0))
+		if (!wildmatch(p, pathbuf, 0, NULL))
 			return 1;
 	}
 	return 0;
builtin/name-rev.c +1 -1
index 0b21d7e..c824d4e 100644
@@ -87,7 +87,7 @@ static int subpath_matches(const char *path, const char *filter)
 	const char *subpath = path;
 
 	while (subpath) {
-		if (!fnmatch(filter, subpath, 0))
+		if (!wildmatch(filter, subpath, 0, NULL))
 			return subpath - path;
 		subpath = strchr(subpath, '/');
 		if (subpath)
builtin/reflog.c +1 -1
index 852cff6..c12a9784 100644
@@ -561,7 +561,7 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, c
 		return; /* both given explicitly -- nothing to tweak */
 
 	for (ent = reflog_expire_cfg; ent; ent = ent->next) {
-		if (!fnmatch(ent->pattern, ref, 0)) {
+		if (!wildmatch(ent->pattern, ref, 0, NULL)) {
 			if (!(slot & EXPIRE_TOTAL))
 				cb->expire_total = ent->expire_total;
 			if (!(slot & EXPIRE_UNREACH))
builtin/replace.c +1 -1
index 2336325..80b152a 100644
@@ -36,7 +36,7 @@ static int show_reference(const char *refname, const unsigned char *sha1,
 {
 	struct show_data *data = cb_data;
 
-	if (!fnmatch(data->pattern, refname, 0)) {
+	if (!wildmatch(data->pattern, refname, 0, NULL)) {
 		if (data->format == REPLACE_FORMAT_SHORT)
 			printf("%s\n", refname);
 		else if (data->format == REPLACE_FORMAT_MEDIUM)
builtin/show-branch.c +1 -1
index d9217ce..d873172 100644
@@ -450,7 +450,7 @@ static int append_matching_ref(const char *refname, const unsigned char *sha1, i
 			slash--;
 	if (!*tail)
 		return 0;
-	if (fnmatch(match_ref_pattern, tail, 0))
+	if (wildmatch(match_ref_pattern, tail, 0, NULL))
 		return 0;
 	if (starts_with(refname, "refs/heads/"))
 		return append_head_ref(refname, sha1, flag, cb_data);
builtin/tag.c +1 -1
index 74d3780..169c676 100644
@@ -42,7 +42,7 @@ static int match_pattern(const char **patterns, const char *ref)
 	if (!*patterns)
 		return 1;
 	for (; *patterns; patterns++)
-		if (!fnmatch(*patterns, ref, 0))
+		if (!wildmatch(*patterns, ref, 0, NULL))
 			return 1;
 	return 0;
 }
diffcore-order.c +1 -1
index fe7f1f4..53ea4d1 100644
@@ -73,7 +73,7 @@ static int match_order(const char *path)
 		strbuf_addstr(&p, path);
 		while (p.buf[0]) {
 			char *cp;
-			if (!fnmatch(order[i], p.buf, 0))
+			if (!wildmatch(order[i], p.buf, 0, NULL))
 				return i;
 			cp = strrchr(p.buf, '/');
 			if (!cp)
dir.c +7 -4
index b35b633..59ccb52 100644
@@ -49,7 +49,9 @@ int strncmp_icase(const char *a, const char *b, size_t count)
 
 int fnmatch_icase(const char *pattern, const char *string, int flags)
 {
-	return fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0));
+	return wildmatch(pattern, string,
+			 flags | (ignore_case ? WM_CASEFOLD : 0),
+			 NULL);
 }
 
 inline int git_fnmatch(const struct pathspec_item *item,
@@ -58,7 +60,7 @@ inline int git_fnmatch(const struct pathspec_item *item,
 {
 	if (prefix > 0) {
 		if (ps_strncmp(item, pattern, string, prefix))
-			return FNM_NOMATCH;
+			return WM_NOMATCH;
 		pattern += prefix;
 		string += prefix;
 	}
@@ -76,8 +78,9 @@ inline int git_fnmatch(const struct pathspec_item *item,
 				 NULL);
 	else
 		/* wildmatch has not learned no FNM_PATHNAME mode yet */
-		return fnmatch(pattern, string,
-			       item->magic & PATHSPEC_ICASE ? FNM_CASEFOLD : 0);
+		return wildmatch(pattern, string,
+				 item->magic & PATHSPEC_ICASE ? WM_CASEFOLD : 0,
+				 NULL);
 }
 
 static int fnmatch_icase_mem(const char *pattern, int patternlen,
refs.c +1 -1
index 89228e2..f89d589 100644
@@ -1477,7 +1477,7 @@ static int filter_refs(const char *refname, const unsigned char *sha1, int flags
 		       void *data)
 {
 	struct ref_filter *filter = (struct ref_filter *)data;
-	if (fnmatch(filter->pattern, refname, 0))
+	if (wildmatch(filter->pattern, refname, 0, NULL))
 		return 0;
 	return filter->fn(refname, sha1, flags, filter->cb_data);
 }
revision.c +1 -1
index a0df72f..6addff1 100644
@@ -1191,7 +1191,7 @@ int ref_excluded(struct string_list *ref_excludes, const char *path)
 	if (!ref_excludes)
 		return 0;
 	for_each_string_list_item(item, ref_excludes) {
-		if (!fnmatch(item->string, path, 0))
+		if (!wildmatch(item->string, path, 0, NULL))
 			return 1;
 	}
 	return 0;
Signature · 1 line
1.8.5.2.240.g8478abd
#2 lore raw

PATCH 2/4 Revert "test-wildmatch: add "perf" command to compare wildmatch and fnmatch"

In reply to Nguyễn Thái Ngọc Duy

This reverts commit 1b25892636d2f250eb2163301440ee8c8c1ac944. compat fnmatch will be removed soon and we can't rely on fnmatch() available everywhere.

---
 test-wildmatch.c | 73 --------------------------------------------------------
 1 file changed, 73 deletions(-)
test-wildmatch.c +0 -73
index a3e2643..1564bd5 100644
@@ -4,82 +4,9 @@
 #include "cache.h"
 #include "wildmatch.h"
 
-static int perf(int ac, char **av)
-{
-	struct timeval tv1, tv2;
-	struct stat st;
-	int fd, i, n, flags1 = 0, flags2 = 0;
-	char *buffer, *p;
-	uint32_t usec1, usec2;
-	const char *lang;
-	const char *file = av[0];
-	const char *pattern = av[1];
-
-	lang = getenv("LANG");
-	if (lang && strcmp(lang, "C"))
-		die("Please test it on C locale.");
-
-	if ((fd = open(file, O_RDONLY)) == -1 || fstat(fd, &st))
-		die_errno("file open");
-
-	buffer = xmalloc(st.st_size + 2);
-	if (read(fd, buffer, st.st_size) != st.st_size)
-		die_errno("read");
-
-	buffer[st.st_size] = '\0';
-	buffer[st.st_size + 1] = '\0';
-	for (i = 0; i < st.st_size; i++)
-		if (buffer[i] == '\n')
-			buffer[i] = '\0';
-
-	n = atoi(av[2]);
-	if (av[3] && !strcmp(av[3], "pathname")) {
-		flags1 = WM_PATHNAME;
-		flags2 = FNM_PATHNAME;
-	}
-
-	gettimeofday(&tv1, NULL);
-	for (i = 0; i < n; i++) {
-		for (p = buffer; *p; p += strlen(p) + 1)
-			wildmatch(pattern, p, flags1, NULL);
-	}
-	gettimeofday(&tv2, NULL);
-
-	usec1 = (uint32_t)tv2.tv_sec * 1000000 + tv2.tv_usec;
-	usec1 -= (uint32_t)tv1.tv_sec * 1000000 + tv1.tv_usec;
-	printf("wildmatch %ds %dus\n",
-	       (int)(usec1 / 1000000),
-	       (int)(usec1 % 1000000));
-
-	gettimeofday(&tv1, NULL);
-	for (i = 0; i < n; i++) {
-		for (p = buffer; *p; p += strlen(p) + 1)
-			fnmatch(pattern, p, flags2);
-	}
-	gettimeofday(&tv2, NULL);
-
-	usec2 = (uint32_t)tv2.tv_sec * 1000000 + tv2.tv_usec;
-	usec2 -= (uint32_t)tv1.tv_sec * 1000000 + tv1.tv_usec;
-	if (usec2 > usec1)
-		printf("fnmatch   %ds %dus or %.2f%% slower\n",
-		       (int)((usec2 - usec1) / 1000000),
-		       (int)((usec2 - usec1) % 1000000),
-		       (float)(usec2 - usec1) / usec1 * 100);
-	else
-		printf("fnmatch   %ds %dus or %.2f%% faster\n",
-		       (int)((usec1 - usec2) / 1000000),
-		       (int)((usec1 - usec2) % 1000000),
-		       (float)(usec1 - usec2) / usec1 * 100);
-	return 0;
-}
-
 int main(int argc, char **argv)
 {
 	int i;
-
-	if (!strcmp(argv[1], "perf"))
-		return perf(argc - 2, argv + 2);
-
 	for (i = 2; i < argc; i++) {
 		if (argv[i][0] == '/')
 			die("Forward slash is not allowed at the beginning of the\n"
Signature · 1 line
1.8.5.2.240.g8478abd
#3 lore raw

PATCH 3/4 Stop using fnmatch (either native or compat)

In reply to Nguyễn Thái Ngọc Duy

Since v1.8.4 (about six months ago) wildmatch is used as default replacement for fnmatch. We have seen only one fix since so wildmatch probably has done a good job as fnmatch replacement. This concludes the fnmatch->wildmatch transition by no longer relying on fnmatch.

---
 Makefile             | 22 ----------------------
 config.mak.uname     | 10 ----------
 configure.ac         | 28 ----------------------------
 git-compat-util.h    | 12 ------------
 t/t3070-wildmatch.sh | 13 -------------
 test-wildmatch.c     |  6 ------
 6 files changed, 91 deletions(-)
Makefile +0 -22
index dddaf4f..ca38f99 100644
@@ -101,14 +101,6 @@ all::
 #
 # Define NO_MKSTEMPS if you don't have mkstemps in the C library.
 #
-# Define NO_FNMATCH if you don't have fnmatch in the C library.
-#
-# Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the
-# FNM_CASEFOLD GNU extension.
-#
-# Define NO_WILDMATCH if you do not want to use Git's wildmatch
-# implementation as fnmatch
-#
 # Define NO_GECOS_IN_PWENT if you don't have pw_gecos in struct passwd
 # in the C library.
 #
@@ -1271,20 +1263,6 @@ endif
 ifdef NO_STRTOULL
 	COMPAT_CFLAGS += -DNO_STRTOULL
 endif
-ifdef NO_FNMATCH
-	COMPAT_CFLAGS += -Icompat/fnmatch
-	COMPAT_CFLAGS += -DNO_FNMATCH
-	COMPAT_OBJS += compat/fnmatch/fnmatch.o
-else
-ifdef NO_FNMATCH_CASEFOLD
-	COMPAT_CFLAGS += -Icompat/fnmatch
-	COMPAT_CFLAGS += -DNO_FNMATCH_CASEFOLD
-	COMPAT_OBJS += compat/fnmatch/fnmatch.o
-endif
-endif
-ifndef NO_WILDMATCH
-	COMPAT_CFLAGS += -DUSE_WILDMATCH
-endif
 ifdef NO_SETENV
 	COMPAT_CFLAGS += -DNO_SETENV
 	COMPAT_OBJS += compat/setenv.o
config.mak.uname +0 -10
index 7d31fad..6069a44 100644
@@ -108,7 +108,6 @@ ifeq ($(uname_S),SunOS)
 	NO_MKDTEMP = YesPlease
 	NO_MKSTEMPS = YesPlease
 	NO_REGEX = YesPlease
-	NO_FNMATCH_CASEFOLD = YesPlease
 	NO_MSGFMT_EXTENDED_OPTIONS = YesPlease
 	HAVE_DEV_TTY = YesPlease
 	ifeq ($(uname_R),5.6)
@@ -259,7 +258,6 @@ ifeq ($(uname_S),IRIX)
 	# issue, comment out the NO_MMAP statement.
 	NO_MMAP = YesPlease
 	NO_REGEX = YesPlease
-	NO_FNMATCH_CASEFOLD = YesPlease
 	SNPRINTF_RETURNS_BOGUS = YesPlease
 	SHELL_PATH = /usr/gnu/bin/bash
 	NEEDS_LIBGEN = YesPlease
@@ -279,7 +277,6 @@ ifeq ($(uname_S),IRIX64)
 	# issue, comment out the NO_MMAP statement.
 	NO_MMAP = YesPlease
 	NO_REGEX = YesPlease
-	NO_FNMATCH_CASEFOLD = YesPlease
 	SNPRINTF_RETURNS_BOGUS = YesPlease
 	SHELL_PATH = /usr/gnu/bin/bash
 	NEEDS_LIBGEN = YesPlease
@@ -296,7 +293,6 @@ ifeq ($(uname_S),HP-UX)
 	NO_UNSETENV = YesPlease
 	NO_HSTRERROR = YesPlease
 	NO_SYS_SELECT_H = YesPlease
-	NO_FNMATCH_CASEFOLD = YesPlease
 	SNPRINTF_RETURNS_BOGUS = YesPlease
 	NO_NSEC = YesPlease
 	ifeq ($(uname_R),B.11.00)
@@ -327,7 +323,6 @@ ifeq ($(uname_S),Windows)
 	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
-	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	# NEEDS_LIBICONV = YesPlease
 	NO_ICONV = YesPlease
@@ -389,13 +384,11 @@ ifeq ($(uname_S),Interix)
 		NO_INET_NTOP = YesPlease
 		NO_INET_PTON = YesPlease
 		NO_SOCKADDR_STORAGE = YesPlease
-		NO_FNMATCH_CASEFOLD = YesPlease
 	endif
 	ifeq ($(uname_R),5.2)
 		NO_INET_NTOP = YesPlease
 		NO_INET_PTON = YesPlease
 		NO_SOCKADDR_STORAGE = YesPlease
-		NO_FNMATCH_CASEFOLD = YesPlease
 	endif
 endif
 ifeq ($(uname_S),Minix)
@@ -440,7 +433,6 @@ ifeq ($(uname_S),NONSTOP_KERNEL)
 	NO_D_TYPE_IN_DIRENT = YesPlease
 	NO_HSTRERROR = YesPlease
 	NO_STRCASESTR = YesPlease
-	NO_FNMATCH_CASEFOLD = YesPlease
 	NO_MEMMEM = YesPlease
 	NO_STRLCPY = YesPlease
 	NO_SETENV = YesPlease
@@ -484,7 +476,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
 	NO_STRLCPY = YesPlease
-	NO_FNMATCH = YesPlease
 	NO_MEMMEM = YesPlease
 	NEEDS_LIBICONV = YesPlease
 	NO_STRTOUMAX = YesPlease
@@ -538,7 +529,6 @@ ifeq ($(uname_S),QNX)
 	EXPAT_NEEDS_XMLPARSE_H = YesPlease
 	HAVE_STRINGS_H = YesPlease
 	NEEDS_SOCKET = YesPlease
-	NO_FNMATCH_CASEFOLD = YesPlease
 	NO_GETPAGESIZE = YesPlease
 	NO_ICONV = YesPlease
 	NO_MEMMEM = YesPlease
configure.ac +0 -28
index 2f43393..24ab738 100644
@@ -901,34 +901,6 @@ GIT_CHECK_FUNC(strcasestr,
 [NO_STRCASESTR=YesPlease])
 GIT_CONF_SUBST([NO_STRCASESTR])
 #
-# Define NO_FNMATCH if you don't have fnmatch
-GIT_CHECK_FUNC(fnmatch,
-[NO_FNMATCH=],
-[NO_FNMATCH=YesPlease])
-GIT_CONF_SUBST([NO_FNMATCH])
-#
-# Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the
-# FNM_CASEFOLD GNU extension.
-AC_CACHE_CHECK([whether the fnmatch function supports the FNMATCH_CASEFOLD GNU extension],
- [ac_cv_c_excellent_fnmatch], [
-AC_EGREP_CPP(yippeeyeswehaveit,
-	AC_LANG_PROGRAM([
-#include <fnmatch.h>
-],
-[#ifdef FNM_CASEFOLD
-yippeeyeswehaveit
-#endif
-]),
-	[ac_cv_c_excellent_fnmatch=yes],
-	[ac_cv_c_excellent_fnmatch=no])
-])
-if test $ac_cv_c_excellent_fnmatch = yes; then
-	NO_FNMATCH_CASEFOLD=
-else
-	NO_FNMATCH_CASEFOLD=YesPlease
-fi
-GIT_CONF_SUBST([NO_FNMATCH_CASEFOLD])
-#
 # Define NO_MEMMEM if you don't have memmem.
 GIT_CHECK_FUNC(memmem,
 [NO_MEMMEM=],
git-compat-util.h +0 -12
index cbd86c3..eaee438 100644
@@ -116,9 +116,6 @@
 #include <sys/time.h>
 #include <time.h>
 #include <signal.h>
-#ifndef USE_WILDMATCH
-#include <fnmatch.h>
-#endif
 #include <assert.h>
 #include <regex.h>
 #include <utime.h>
@@ -304,16 +301,7 @@ extern char *gitbasename(char *);
 
 #include "compat/bswap.h"
 
-#ifdef USE_WILDMATCH
 #include "wildmatch.h"
-#define FNM_PATHNAME WM_PATHNAME
-#define FNM_CASEFOLD WM_CASEFOLD
-#define FNM_NOMATCH  WM_NOMATCH
-static inline int fnmatch(const char *pattern, const char *string, int flags)
-{
-	return wildmatch(pattern, string, flags, NULL);
-}
-#endif
 
 /* General helper functions */
 extern void vreportf(const char *prefix, const char *err, va_list params);
t/t3070-wildmatch.sh +0 -13
index 38446a0..ef509df 100755
@@ -14,19 +14,6 @@ match() {
 	    ! test-wildmatch wildmatch '$3' '$4'
 	"
     fi
-    if [ $2 = 1 ]; then
-	test_expect_success "fnmatch:       match '$3' '$4'" "
-	    test-wildmatch fnmatch '$3' '$4'
-	"
-    elif [ $2 = 0 ]; then
-	test_expect_success "fnmatch:    no match '$3' '$4'" "
-	    ! test-wildmatch fnmatch '$3' '$4'
-	"
-#    else
-#	test_expect_success BROKEN_FNMATCH "fnmatch:       '$3' '$4'" "
-#	    ! test-wildmatch fnmatch '$3' '$4'
-#	"
-    fi
 }
 
 imatch() {
test-wildmatch.c +0 -6
index 1564bd5..578b164 100644
@@ -1,8 +1,4 @@
-#ifdef USE_WILDMATCH
-#undef USE_WILDMATCH  /* We need real fnmatch implementation here */
-#endif
 #include "cache.h"
-#include "wildmatch.h"
 
 int main(int argc, char **argv)
 {
@@ -20,8 +16,6 @@ int main(int argc, char **argv)
 		return !!wildmatch(argv[3], argv[2], WM_PATHNAME | WM_CASEFOLD, NULL);
 	else if (!strcmp(argv[1], "pathmatch"))
 		return !!wildmatch(argv[3], argv[2], 0, NULL);
-	else if (!strcmp(argv[1], "fnmatch"))
-		return !!fnmatch(argv[3], argv[2], FNM_PATHNAME);
 	else
 		return 1;
 }
Signature · 1 line
1.8.5.2.240.g8478abd
#4 lore raw

PATCH 4/4 Actually remove compat fnmatch source code

In reply to Nguyễn Thái Ngọc Duy
---
 compat/fnmatch/fnmatch.c (gone) | 494 ----------------------------------------
 compat/fnmatch/fnmatch.h (gone) |  84 -------
 2 files changed, 578 deletions(-)
compat/fnmatch/fnmatch.c deleted +0 -494
deleted file mode 100644
index 378c467..0000000
@@ -1,494 +0,0 @@
-/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   This library 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
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with this library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-/* Enable GNU extensions in fnmatch.h.  */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE	1
-#endif
-
-#include <stddef.h>
-#include <errno.h>
-#include <fnmatch.h>
-#include <ctype.h>
-
-#if HAVE_STRING_H || defined _LIBC
-# include <string.h>
-#else
-# include <strings.h>
-#endif
-
-#if defined STDC_HEADERS || defined _LIBC
-# include <stdlib.h>
-#endif
-
-/* For platforms which support the ISO C amendment 1 functionality we
-   support user defined character classes.  */
-#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
-/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
-# include <wchar.h>
-# include <wctype.h>
-#endif
-
-/* Comment out all this code if we are using the GNU C Library, and are not
-   actually compiling the library itself.  This code is part of the GNU C
-   Library, but also included in many other GNU distributions.  Compiling
-   and linking in this code is a waste when using the GNU C library
-   (especially if it is a shared library).  Rather than having every GNU
-   program understand `configure --with-gnu-libc' and omit the object files,
-   it is simpler to just do this in the source for each such file.  */
-
-#if defined NO_FNMATCH || defined NO_FNMATCH_CASEFOLD || \
-    defined _LIBC || !defined __GNU_LIBRARY__
-
-
-# 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))
-
-# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
-
-# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
-/* The GNU C library provides support for user-defined character classes
-   and the functions from ISO C amendment 1.  */
-#  ifdef CHARCLASS_NAME_MAX
-#   define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
-#  else
-/* This shouldn't happen but some implementation might still have this
-   problem.  Use a reasonable default value.  */
-#   define CHAR_CLASS_MAX_LENGTH 256
-#  endif
-
-#  ifdef _LIBC
-#   define IS_CHAR_CLASS(string) __wctype (string)
-#  else
-#   define IS_CHAR_CLASS(string) wctype (string)
-#  endif
-# else
-#  define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
-
-#  define IS_CHAR_CLASS(string)						      \
-   (STREQ (string, "alpha") || STREQ (string, "upper")			      \
-    || STREQ (string, "lower") || STREQ (string, "digit")		      \
-    || STREQ (string, "alnum") || STREQ (string, "xdigit")		      \
-    || STREQ (string, "space") || STREQ (string, "print")		      \
-    || STREQ (string, "punct") || STREQ (string, "graph")		      \
-    || STREQ (string, "cntrl") || STREQ (string, "blank"))
-# endif
-
-/* Avoid depending on library functions or files
-   whose names are inconsistent.  */
-
-# if !defined _LIBC && !defined getenv
-extern char *getenv (const char *name);
-# endif
-
-# ifndef errno
-extern int errno;
-# endif
-
-# ifndef NULL
-#  define NULL 0
-# endif
-
-/* This function doesn't exist on most systems.  */
-
-# if !defined HAVE___STRCHRNUL && !defined _LIBC
-static char *
-__strchrnul (const char *s, int c)
-
-
-{
-  char *result = strchr (s, c);
-  if (result == NULL)
-    result = strchr (s, '\0');
-  return result;
-}
-# endif
-
-# ifndef internal_function
-/* Inside GNU libc we mark some function in a special way.  In other
-   environments simply ignore the marking.  */
-#  define internal_function
-# endif
-
-/* Match STRING against the filename pattern PATTERN, returning zero if
-   it matches, nonzero if not.  */
-static int internal_fnmatch __P ((const char *pattern, const char *string,
-				  int no_leading_period, int flags))
-     internal_function;
-static int
-internal_function
-internal_fnmatch (const char *pattern, const char *string, int no_leading_period, int flags)
-
-
-
-
-{
-  register const char *p = pattern, *n = string;
-  register unsigned char c;
-
-/* Note that this evaluates C many times.  */
-# ifdef _LIBC
-#  define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
-# else
-#  define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
-# endif
-
-  while ((c = *p++) != '\0')
-    {
-      c = FOLD (c);
-
-      switch (c)
-	{
-	case '?':
-	  if (*n == '\0')
-	    return FNM_NOMATCH;
-	  else if (*n == '/' && (flags & FNM_FILE_NAME))
-	    return FNM_NOMATCH;
-	  else if (*n == '.' && no_leading_period
-		   && (n == string
-		       || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
-	    return FNM_NOMATCH;
-	  break;
-
-	case '\\':
-	  if (!(flags & FNM_NOESCAPE))
-	    {
-	      c = *p++;
-	      if (c == '\0')
-		/* Trailing \ loses.  */
-		return FNM_NOMATCH;
-	      c = FOLD (c);
-	    }
-	  if (FOLD ((unsigned char) *n) != c)
-	    return FNM_NOMATCH;
-	  break;
-
-	case '*':
-	  if (*n == '.' && no_leading_period
-	      && (n == string
-		  || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
-	    return FNM_NOMATCH;
-
-	  for (c = *p++; c == '?' || c == '*'; c = *p++)
-	    {
-	      if (*n == '/' && (flags & FNM_FILE_NAME))
-		/* A slash does not match a wildcard under FNM_FILE_NAME.  */
-		return FNM_NOMATCH;
-	      else if (c == '?')
-		{
-		  /* A ? needs to match one character.  */
-		  if (*n == '\0')
-		    /* There isn't another character; no match.  */
-		    return FNM_NOMATCH;
-		  else
-		    /* One character of the string is consumed in matching
-		       this ? wildcard, so *??? won't match if there are
-		       less than three characters.  */
-		    ++n;
-		}
-	    }
-
-	  if (c == '\0')
-	    /* The wildcard(s) is/are the last element of the pattern.
-	       If the name is a file name and contains another slash
-	       this does mean it cannot match.  */
-	    return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL
-		    ? FNM_NOMATCH : 0);
-	  else
-	    {
-	      const char *endp;
-
-	      endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0');
-
-	      if (c == '[')
-		{
-		  int flags2 = ((flags & FNM_FILE_NAME)
-				? flags : (flags & ~FNM_PERIOD));
-
-		  for (--p; n < endp; ++n)
-		    if (internal_fnmatch (p, n,
-					  (no_leading_period
-					   && (n == string
-					       || (n[-1] == '/'
-						   && (flags
-						       & FNM_FILE_NAME)))),
-					  flags2)
-			== 0)
-		      return 0;
-		}
-	      else if (c == '/' && (flags & FNM_FILE_NAME))
-		{
-		  while (*n != '\0' && *n != '/')
-		    ++n;
-		  if (*n == '/'
-		      && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
-					    flags) == 0))
-		    return 0;
-		}
-	      else
-		{
-		  int flags2 = ((flags & FNM_FILE_NAME)
-				? flags : (flags & ~FNM_PERIOD));
-
-		  if (c == '\\' && !(flags & FNM_NOESCAPE))
-		    c = *p;
-		  c = FOLD (c);
-		  for (--p; n < endp; ++n)
-		    if (FOLD ((unsigned char) *n) == c
-			&& (internal_fnmatch (p, n,
-					      (no_leading_period
-					       && (n == string
-						   || (n[-1] == '/'
-						       && (flags
-							   & FNM_FILE_NAME)))),
-					      flags2) == 0))
-		      return 0;
-		}
-	    }
-
-	  /* If we come here no match is possible with the wildcard.  */
-	  return FNM_NOMATCH;
-
-	case '[':
-	  {
-	    /* Nonzero if the sense of the character class is inverted.  */
-	    static int posixly_correct;
-	    register int not;
-	    char cold;
-
-	    if (posixly_correct == 0)
-	      posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
-
-	    if (*n == '\0')
-	      return FNM_NOMATCH;
-
-	    if (*n == '.' && no_leading_period && (n == string
-						   || (n[-1] == '/'
-						       && (flags
-							   & FNM_FILE_NAME))))
-	      return FNM_NOMATCH;
-
-	    if (*n == '/' && (flags & FNM_FILE_NAME))
-	      /* `/' cannot be matched.  */
-	      return FNM_NOMATCH;
-
-	    not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
-	    if (not)
-	      ++p;
-
-	    c = *p++;
-	    for (;;)
-	      {
-		unsigned char fn = FOLD ((unsigned char) *n);
-
-		if (!(flags & FNM_NOESCAPE) && c == '\\')
-		  {
-		    if (*p == '\0')
-		      return FNM_NOMATCH;
-		    c = FOLD ((unsigned char) *p);
-		    ++p;
-
-		    if (c == fn)
-		      goto matched;
-		  }
-		else if (c == '[' && *p == ':')
-		  {
-		    /* Leave room for the null.  */
-		    char str[CHAR_CLASS_MAX_LENGTH + 1];
-		    size_t c1 = 0;
-# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
-		    wctype_t wt;
-# endif
-		    const char *startp = p;
-
-		    for (;;)
-		      {
-			if (c1 > CHAR_CLASS_MAX_LENGTH)
-			  /* The name is too long and therefore the pattern
-			     is ill-formed.  */
-			  return FNM_NOMATCH;
-
-			c = *++p;
-			if (c == ':' && p[1] == ']')
-			  {
-			    p += 2;
-			    break;
-			  }
-			if (c < 'a' || c >= 'z')
-			  {
-			    /* This cannot possibly be a character class name.
-			       Match it as a normal range.  */
-			    p = startp;
-			    c = '[';
-			    goto normal_bracket;
-			  }
-			str[c1++] = c;
-		      }
-		    str[c1] = '\0';
-
-# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
-		    wt = IS_CHAR_CLASS (str);
-		    if (wt == 0)
-		      /* Invalid character class name.  */
-		      return FNM_NOMATCH;
-
-		    if (__iswctype (__btowc ((unsigned char) *n), wt))
-		      goto matched;
-# else
-		    if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n))
-			|| (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n))
-			|| (STREQ (str, "blank") && ISBLANK ((unsigned char) *n))
-			|| (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n))
-			|| (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n))
-			|| (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n))
-			|| (STREQ (str, "lower") && ISLOWER ((unsigned char) *n))
-			|| (STREQ (str, "print") && ISPRINT ((unsigned char) *n))
-			|| (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n))
-			|| (STREQ (str, "space") && ISSPACE ((unsigned char) *n))
-			|| (STREQ (str, "upper") && ISUPPER ((unsigned char) *n))
-			|| (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n)))
-		      goto matched;
-# endif
-		  }
-		else if (c == '\0')
-		  /* [ (unterminated) loses.  */
-		  return FNM_NOMATCH;
-		else
-		  {
-		  normal_bracket:
-		    if (FOLD (c) == fn)
-		      goto matched;
-
-		    cold = c;
-		    c = *p++;
-
-		    if (c == '-' && *p != ']')
-		      {
-			/* It is a range.  */
-			unsigned char cend = *p++;
-			if (!(flags & FNM_NOESCAPE) && cend == '\\')
-			  cend = *p++;
-			if (cend == '\0')
-			  return FNM_NOMATCH;
-
-			if (cold <= fn && fn <= FOLD (cend))
-			  goto matched;
-
-			c = *p++;
-		      }
-		  }
-
-		if (c == ']')
-		  break;
-	      }
-
-	    if (!not)
-	      return FNM_NOMATCH;
-	    break;
-
-	  matched:
-	    /* Skip the rest of the [...] that already matched.  */
-	    while (c != ']')
-	      {
-		if (c == '\0')
-		  /* [... (unterminated) loses.  */
-		  return FNM_NOMATCH;
-
-		c = *p++;
-		if (!(flags & FNM_NOESCAPE) && c == '\\')
-		  {
-		    if (*p == '\0')
-		      return FNM_NOMATCH;
-		    /* XXX 1003.2d11 is unclear if this is right.  */
-		    ++p;
-		  }
-		else if (c == '[' && *p == ':')
-		  {
-		    do
-		      if (*++p == '\0')
-			return FNM_NOMATCH;
-		    while (*p != ':' || p[1] == ']');
-		    p += 2;
-		    c = *p;
-		  }
-	      }
-	    if (not)
-	      return FNM_NOMATCH;
-	  }
-	  break;
-
-	default:
-	  if (c != FOLD ((unsigned char) *n))
-	    return FNM_NOMATCH;
-	}
-
-      ++n;
-    }
-
-  if (*n == '\0')
-    return 0;
-
-  if ((flags & FNM_LEADING_DIR) && *n == '/')
-    /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
-    return 0;
-
-  return FNM_NOMATCH;
-
-# undef FOLD
-}
-
-
-int
-fnmatch (const char *pattern, const char *string, int flags)
-
-
-
-{
-  return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
-}
-
-#endif	/* _LIBC or not __GNU_LIBRARY__.  */
compat/fnmatch/fnmatch.h deleted +0 -84

84 lines not on this page · raw message

Signature · 1 line
1.8.5.2.240.g8478abd
#5 lore raw
In reply to Nguyễn Thái Ngọc Duy
Quoted 2 lines · Nguyễn Thái Ngọc Duy

Long story short, we wanted globbing wildcard "**" so I ripped wildmatch library from rsync to do it.

Since version 3.0.0, rsync is GPLv3 <URL:https://rsync.samba.org/GPL.html>. So be sure to take an older version.

Quoted 6 lines

And it opened a possibility to replace fnmatch completely, which would provide consistent behavior across platforms (native fnmatch behaves differently on many corner cases), and some performance gains. I started fnmatch replacement with 4917e1e (Makefile: promote wildmatch to be the default fnmatch implementation - 2013-05-30). This is the final step.

Sounds like I'm, uh, somewhat late in the game. More likely than not you've taken care of that aspect long ago. Just thought I'd mention it.

Signature · 1 line
David Kastrup
author
#6 lore raw
Quoted 8 lines · David Kastrup
Quoted 2 lines · Nguyễn Thái Ngọc Duy

Long story short, we wanted globbing wildcard "**" so I ripped wildmatch library from rsync to do it.

Since version 3.0.0, rsync is GPLv3 <URL:https://rsync.samba.org/GPL.html>. So be sure to take an older version.

Yes. See 5230f60 (Import wildmatch from rsync - 2012-10-15), the code was taken from the last GPL-2 commit.

Signature · 1 line
Duy
#7 lore raw
Quoted 6 lines · Duy Nguyen
Quoted 5 lines · David Kastrup
Quoted 2 lines · Nguyễn Thái Ngọc Duy

Long story short, we wanted globbing wildcard "**" so I ripped wildmatch library from rsync to do it.

Quoted 6 lines
Quoted 3 lines

Since version 3.0.0, rsync is GPLv3 <URL:https://rsync.samba.org/GPL.html>. So be sure to take an older version.

Yes. See 5230f60 (Import wildmatch from rsync - 2012-10-15), the code was taken from the last GPL-2 commit.

Thanks.

Signature · 1 line
David Kastrup
#8 lore raw
In reply to Nguyễn Thái Ngọc Duy
Quoted 7 lines · Nguyễn Thái Ngọc Duy

Long story short, we wanted globbing wildcard "**" so I ripped wildmatch library from rsync to do it. And it opened a possibility to replace fnmatch completely, which would provide consistent behavior across platforms (native fnmatch behaves differently on many corner cases), and some performance gains. I started fnmatch replacement with 4917e1e (Makefile: promote wildmatch to be the default fnmatch implementation - 2013-05-30). This is the final step.

Nice.

Quoted 30 lines

Nguyễn Thái Ngọc Duy (4):
Use wildmatch() directly without fnmatch() wrapper
Revert "test-wildmatch: add "perf" command to compare wildmatch and fnmatch" Stop using fnmatch (either native or compat)
Actually remove compat fnmatch source code

 Makefile                        |  22 --
 builtin/apply.c                 |   2 +-
 builtin/branch.c                |   2 +-
 builtin/describe.c              |   2 +-
 builtin/for-each-ref.c          |   2 +-
 builtin/ls-remote.c             |   2 +-
 builtin/name-rev.c              |   2 +-
 builtin/reflog.c                |   2 +-
 builtin/replace.c               |   2 +-
 builtin/show-branch.c           |   2 +-
 builtin/tag.c                   |   2 +-
 compat/fnmatch/fnmatch.c (gone) | 494 ----------------------------------------
 compat/fnmatch/fnmatch.h (gone) |  84 -------
 config.mak.uname                |  10 -
 configure.ac                    |  28 ---
 diffcore-order.c                |   2 +-
 dir.c                           |  11 +-
 git-compat-util.h               |  12 -
 refs.c                          |   2 +-
 revision.c                      |   2 +-
 t/t3070-wildmatch.sh            |  13 --
 test-wildmatch.c                |  79 -------
 22 files changed, 20 insertions(+), 759 deletions(-)