Good bye fnmatch
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
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
@@ -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
@@ -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
@@ -150,7 +150,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, voidreturn 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
@@ -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
@@ -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
@@ -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
@@ -561,7 +561,7 @@ static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, creturn ;/* 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
PATCH 2/4 Revert "test-wildmatch: add "perf" command to compare wildmatch and fnmatch"
In reply to Nguyễn Thái Ngọc DuyThis 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
@@ -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
PATCH 3/4 Stop using fnmatch (either native or compat)
In reply to Nguyễn Thái Ngọc DuySince 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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
@@ -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 definedSTDC_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 || (definedHAVE_WCTYPE_H && definedHAVE_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 definedNO_FNMATCH || definedNO_FNMATCH_CASEFOLD || \ - defined _LIBC || !defined __GNU_LIBRARY__ - - -# if definedSTDC_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 || (definedHAVE_WCTYPE_H && definedHAVE_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 !definedHAVE___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) - - - - -{ - registerconst char *p = pattern, *n = string; - registerunsigned 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; - registerint 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 || (definedHAVE_WCTYPE_H && definedHAVE_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 || (definedHAVE_WCTYPE_H && definedHAVE_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
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
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
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
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):
Usewildmatch()directly withoutfnmatch()wrapper
Revert "test-wildmatch: add "perf" command to compare wildmatch and fnmatch" Stop using fnmatch (either native or compat)
Actually remove compat fnmatch source codeMakefile | 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(-)