X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/c627d61324e9dcd5df833ee6236dd10415f5bac4..592f4696dc0f9d8f8f79b39375ea047db6cefe85:/lib/fnmatch.c diff --git a/lib/fnmatch.c b/lib/fnmatch.c index 6befc3b9..2feeac51 100644 --- a/lib/fnmatch.c +++ b/lib/fnmatch.c @@ -1,33 +1,60 @@ #include "../rsync.h" #ifndef HAVE_FNMATCH -/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. +/* ----- THE FOLLOWING UP TO 'END' is glibc-2.1.2 posix/fnmatch.c + except for the parts with '#if 0' */ -NOTE: The canonical source of this file is maintained with the GNU C Library. -Bugs can be reported to bug-glibc@prep.ai.mit.edu. +/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc. + This file is part of the GNU C Library. -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. + 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 program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + 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 General Public License -along with this program; if not, write to the Free Software -Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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 defined (STDC_HEADERS) || !defined (isascii) -#define ISASCII(c) 1 +#if 0 /* header files included better by ../rsync.h */ + +#if HAVE_CONFIG_H +# include +#endif + +/* Enable GNU extensions in fnmatch.h. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#include +#include +#include + +#if HAVE_STRING_H || defined _LIBC +# include #else -#define ISASCII(c) isascii(c) +# include #endif -#define ISUPPER(c) (ISASCII (c) && isupper (c)) +#if defined STDC_HEADERS || defined _LIBC +# include +#endif +#endif /* 0 */ +/* For platform which support the ISO C amendement 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: must be included before . */ +# include +# include +#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 @@ -37,23 +64,95 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 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(__GNU_LIBRARY__) && !defined(STDC_HEADERS) -extern int errno; +#if 1 + +# 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 amendement 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 (); +# endif + +# ifndef errno +extern int errno; +# endif /* Match STRING against the filename pattern PATTERN, returning zero if it matches, nonzero if not. */ -int -fnmatch (pattern, string, flags) - const char *pattern; - const char *string; - int flags; +static int +#ifdef _LIBC +internal_function +#endif +internal_fnmatch (const char *pattern, const char *string, + int no_leading_period, int flags) { register const char *p = pattern, *n = string; - register char c; + register unsigned char c; -/* Note that this evalutes C many times. */ -#define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (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') { @@ -64,10 +163,11 @@ fnmatch (pattern, string, flags) case '?': if (*n == '\0') return FNM_NOMATCH; - else if ((flags & FNM_FILE_NAME) && *n == '/') + else if (*n == '/' && (flags & FNM_FILE_NAME)) return FNM_NOMATCH; - else if ((flags & FNM_PERIOD) && *n == '.' && - (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + else if (*n == '.' && no_leading_period + && (n == string + || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) return FNM_NOMATCH; break; @@ -75,95 +175,245 @@ fnmatch (pattern, string, flags) if (!(flags & FNM_NOESCAPE)) { c = *p++; + if (c == '\0') + /* Trailing \ loses. */ + return FNM_NOMATCH; c = FOLD (c); } - if (FOLD (*n) != c) + if (FOLD ((unsigned char) *n) != c) return FNM_NOMATCH; break; case '*': - if ((flags & FNM_PERIOD) && *n == '.' && - (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + if (*n == '.' && no_leading_period + && (n == string + || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) return FNM_NOMATCH; - for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) - if (((flags & FNM_FILE_NAME) && *n == '/') || - (c == '?' && *n == '\0')) - 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') - return 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; - { - char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; - c1 = FOLD (c1); - for (--p; *n != '\0'; ++n) - if ((c == '[' || FOLD (*n) == c1) && - fnmatch (p, n, flags & ~FNM_PERIOD) == 0) - return 0; - return FNM_NOMATCH; - } +#if 0 + endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0'); +#else +/* replace call to internal glibc function with equivalent */ + if (!(flags & FNM_FILE_NAME) || ((endp = strchr(n, '/')) == NULL)) + endp = n + strlen(n); +#endif + + 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 ((flags & FNM_PERIOD) && *n == '.' && - (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + 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 == '!' || *p == '^'); + not = (*p == '!' || (posixly_correct < 0 && *p == '^')); if (not) ++p; c = *p++; for (;;) { - register char cstart = c, cend = c; + unsigned char fn = FOLD ((unsigned char) *n); if (!(flags & FNM_NOESCAPE) && c == '\\') - cstart = cend = *p++; + { + if (*p == '\0') + return FNM_NOMATCH; + c = FOLD ((unsigned char) *p); + ++p; - cstart = cend = FOLD (cstart); + 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 (c == '\0') + 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; - c = *p++; - c = FOLD (c); + cold = c; + c = *p++; - if ((flags & FNM_FILE_NAME) && c == '/') - /* [/] can never match. */ - return FNM_NOMATCH; + 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 (c == '-' && *p != ']') - { - cend = *p++; - if (!(flags & FNM_NOESCAPE) && cend == '\\') - cend = *p++; - if (cend == '\0') - return FNM_NOMATCH; - cend = FOLD (cend); + if (cold <= fn && fn <= FOLD (cend)) + goto matched; - c = *p++; + c = *p++; + } } - if (FOLD (*n) >= cstart && FOLD (*n) <= cend) - goto matched; - if (c == ']') break; } + if (!not) return FNM_NOMATCH; break; - matched:; + matched: /* Skip the rest of the [...] that already matched. */ while (c != ']') { @@ -173,8 +423,21 @@ fnmatch (pattern, string, flags) c = *p++; if (!(flags & FNM_NOESCAPE) && c == '\\') - /* XXX 1003.2d11 is unclear if this is right. */ - ++p; + { + 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; @@ -182,7 +445,7 @@ fnmatch (pattern, string, flags) break; default: - if (c != FOLD (*n)) + if (c != FOLD ((unsigned char) *n)) return FNM_NOMATCH; } @@ -197,8 +460,23 @@ fnmatch (pattern, string, flags) return 0; return FNM_NOMATCH; + +# undef FOLD } + +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ +/* ----- END glibc-2.1.2 posix/fnmatch.c */ + #else /* HAVE_FNMATCH */ void fnmatch_dummy(void) {} #endif