diff options
author | Bruno Haible <bruno@clisp.org> | 2001-12-18 13:42:35 +0000 |
---|---|---|
committer | Bruno Haible <bruno@clisp.org> | 2009-06-21 23:50:24 +0200 |
commit | 2470ca28e843e6bca8ba474fc01976adee802aa2 (patch) | |
tree | 0eb1fc0efc0680c6724ae015ba922e8a2a92f56f /lib/pfnmatch.c | |
parent | b4eabed43045d533620e99911de1ec4b11c2a74f (diff) | |
download | external_gettext-2470ca28e843e6bca8ba474fc01976adee802aa2.zip external_gettext-2470ca28e843e6bca8ba474fc01976adee802aa2.tar.gz external_gettext-2470ca28e843e6bca8ba474fc01976adee802aa2.tar.bz2 |
msggrep --location now accepts wildcards.
Diffstat (limited to 'lib/pfnmatch.c')
-rw-r--r-- | lib/pfnmatch.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/lib/pfnmatch.c b/lib/pfnmatch.c new file mode 100644 index 0000000..e2c897a --- /dev/null +++ b/lib/pfnmatch.c @@ -0,0 +1,211 @@ +/* POSIX fnmatch(). + Copyright 1991-1993, 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + + 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 program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Enable GNU extensions in fnmatch.h. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +/* Specification. */ +#include "fnmatch.h" + +#include <errno.h> + + +/* 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; +{ + register const char *p = pattern, *n = string; + register char c; + + while ((c = *p++) != '\0') + { + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if ((flags & FNM_FILE_NAME) && *n == '/') + return FNM_NOMATCH; + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + if (c == '\0') + /* Trailing \ loses. */ + return FNM_NOMATCH; + } + if (*n != c) + return FNM_NOMATCH; + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++) + { + if (c == '?') + { + /* A ? needs to match one character. */ + if (*n == '\0' || (*n == '/' && (flags & FNM_FILE_NAME))) + /* 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') + { + if ((flags & (FNM_FILE_NAME | FNM_LEADING_DIR)) == FNM_FILE_NAME) + for (; *n != '\0'; n++) + if (*n == '/') + return FNM_NOMATCH; + return 0; + } + + { + char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + for (--p; *n != '\0'; ++n) + if ((c == '[' || *n == c1) && + fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + return 0; + else if (*n == '/' && (flags & FNM_FILE_NAME)) + break; + return FNM_NOMATCH; + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int not; + + if (*n == '\0') + return FNM_NOMATCH; + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) + { + register char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + { + if (*p == '\0') + return FNM_NOMATCH; + cstart = cend = *p++; + } + + cend = cstart; + + if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + + if ((flags & FNM_FILE_NAME) && c == '/') + /* [/] can never match. */ + return FNM_NOMATCH; + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + + c = *p++; + } + + if ((unsigned char) *n >= (unsigned char) cstart + && (unsigned char) *n <= (unsigned char) cend) + goto matched; + + 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; + } + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (c != *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; +} |