/* $Id: fnmatch.c,v 1.5 2003/02/11 11:55:16 aa5779 Exp $ */ /* fnmatch.c -- a special implementation for `fnmatch' */ /* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. * (C) 2002 Artem V. Andreev 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include /* 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(__GNU_LIBRARY__) && !defined(STDC_HEADERS) extern int errno; #endif static int match_char_class(const char *class, int ch); /* Match STRING against the filename pattern PATTERN, returning zero if it matches, nonzero if not. */ static int cs_fnmatch (const char *pattern, const char *string, int flags); static int ci_fnmatch (const char *pattern, const char *string, int flags); int quick_fnmatch (const char *pattern, const char *string, int flags) { return ((flags & FNM_CASEFOLD) ? ci_fnmatch : cs_fnmatch)(pattern, string, flags); } static int cs_fnmatch (const char *pattern, const char *string, int flags) { register const char *p = pattern, *n = string; register char c; /* Note that this evalutes C many times. */ while ((c = *p++) != '\0') { switch (c) { case '?': if (*n == '\0') return FNM_NOMATCH; break; case '\\': c = *p++; if (*n != c) return FNM_NOMATCH; break; case '*': for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) if (c == '?' && *n == '\0') return FNM_NOMATCH; if (c == '\0') return 0; { char c1 = c == '\\' ? *p : c; for (--p; *n != '\0'; ++n) if ((c == '[' || *n == c1) && fnmatch (p, n, flags) == 0) return 0; return FNM_NOMATCH; } case '[': { /* Nonzero if the sense of the character class is inverted. */ register int not, fg; if (*n == '\0') return FNM_NOMATCH; not = (*p == '!' || *p == '^'); if (not) ++p; c = *p++; for (;;) { register char cstart = c, cend = c; if (c == '\\') cstart = cend = *p++; else if( c == '[' && *p == ':') { fg = match_char_class(p, *n); p += 7; if(*p != ']') p++; if(*p != ']') return FNM_NOMATCH; p++; c = *p++; if(fg) goto matched; else if(c == ']') break; else continue; } if (c == '\0') /* [ (unterminated) loses. */ return FNM_NOMATCH; c = *p++; if (c == '-' && *p != ']') { cend = *p++; if (cend == '\\') cend = *p++; if (cend == '\0') return FNM_NOMATCH; c = *p++; } if (*n >= cstart && *n <= cend) goto matched; if (c == ']') break; } if (!not) return FNM_NOMATCH; break; matched:; /* Skip the rest of the [...] that already matched. */ if (not) return FNM_NOMATCH; while (c != ']') { if (c == '\0') /* [... (unterminated) loses. */ return FNM_NOMATCH; if (c == '[' && *p == ':') { p++; c = *p++; while(c != ':') c = *p++; c= *p++; } c = *p++; if (c == '\\') /* XXX 1003.2d11 is unclear if this is right. */ ++p; } } break; default: if (c != *n) return FNM_NOMATCH; } ++n; } if (*n == '\0') return 0; return FNM_NOMATCH; } static int ci_fnmatch (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; break; case '\\': c = *p++; if (tolower(*n) != tolower(c)) return FNM_NOMATCH; break; case '*': for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) if (c == '?' && *n == '\0') return FNM_NOMATCH; if (c == '\0') return 0; { char c1 = tolower(c == '\\' ? *p : c); for (--p; *n != '\0'; ++n) if ((c == '[' || tolower(*n) == c1) && fnmatch (p, n, flags) == 0) return 0; return FNM_NOMATCH; } case '[': { /* Nonzero if the sense of the character class is inverted. */ register int not, fg; if (*n == '\0') return FNM_NOMATCH; not = (*p == '!' || *p == '^'); if (not) ++p; c = *p++; for (;;) { register char cstart = c, cend = c; if (c == '\\') cstart = cend = *p++; else if( c == '[' && *p == ':') { fg = match_char_class(p, *n); p += 7; if(*p != ']') p++; if(*p != ']') return FNM_NOMATCH; p++; c = *p++; if(fg) goto matched; else if(c == ']') break; else continue; } if (c == '\0') /* [ (unterminated) loses. */ return FNM_NOMATCH; c = *p++; if (c == '-' && *p != ']') { cend = *p++; if (cend == '\\') cend = *p++; if (cend == '\0') return FNM_NOMATCH; c = *p++; } if (tolower(*n) >= tolower(cstart) && tolower(*n) <= tolower(cend)) goto matched; if (c == ']') break; } if (!not) return FNM_NOMATCH; break; matched:; /* Skip the rest of the [...] that already matched. */ if (not) return FNM_NOMATCH; while (c != ']') { if (c == '\0') /* [... (unterminated) loses. */ return FNM_NOMATCH; if (c == '[' && *p == ':') { p++; c = *p++; while(c != ':') c = *p++; c= *p++; } c = *p++; if (c == '\\') /* XXX 1003.2d11 is unclear if this is right. */ ++p; } } break; default: if (tolower(c) != tolower(*n)) return FNM_NOMATCH; } ++n; } if (*n == '\0') return 0; return FNM_NOMATCH; } static int match_char_class(const char *class, int ch) { if(!strncmp(class, ":alpha:", 7)) return isalpha(ch); else if(!strncmp(class, ":digit:", 7)) return isdigit(ch); else if(!strncmp(class, ":alnum:", 7)) return isalnum(ch); else if(!strncmp(class, ":upper:", 7)) return isupper(ch); else if(!strncmp(class, ":lower:", 7)) return islower(ch); else if(!strncmp(class, ":space:", 7)) return isspace(ch); else if(!strncmp(class, ":punct:", 7)) return ispunct(ch); else if(!strncmp(class, ":graph:", 7)) return isgraph(ch); else if(!strncmp(class, ":cntrl:", 7)) return iscntrl(ch); else if(!strncmp(class, ":print:", 7)) return isprint(ch); else if(!strncmp(class, ":xdigit:", 8)) return isxdigit(ch); else if(!strncmp(class, ":blank:", 7)) return ch == ' ' || ch == '\t'; else return 0; }