/* $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 <errno.h>
#include <string.h>
#include <gfnmatch.h>
#include <ctype.h>
/* 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;
}
syntax highlighted by Code2HTML, v. 0.9.1