Listing 2: The functions that do actual pattern matching
/*--------------------------------------------------------------*/
/* Copyright (c)1997 by David R. Tribble, all rights reserved. */
/*--------------------------------------------------------------*/
/*
* fpattern_submatch()
* Attempts to match subpattern 'pat' to subfilename 'fname'.
*
* Returns
* 1 (true) if the subfilename matches, otherwise 0 (false).
*
* Caveats
* This does not assume that 'pat' is well-formed.
*
* If 'pat' is empty (""), the only filename it matches is the
* empty ("") string.
*
* Some non-empty patterns (e.g., "") will match an empty
* filename ("").
*/
static int fpattern_submatch(const char *pat, const char *fname)
{
int fch;
int pch;
int i;
int yes, match;
int lo, hi;
/* Attempt to match subpattern against subfilename */
while (*pat != '\0')
{
fch = *fname;
pch = *pat;
pat++;
switch (pch)
{
case FPAT_ANY:
/* Match a single char */
#if DELIM
if (fch == DEL || fch == DEL2 || fch == '\0')
#else
if (fch == '\0')
#endif
{
return (FALSE);
}
fname++;
break;
case FPAT_CLOS:
/* Match zero or more chars */
i = 0;
#if DELIM
while (fname[i] != '\0' &&
fname[i] != DEL && fname[i] != DEL2)
i++;
#else
while (fname[i] != '\0')
i++;
#endif
while (i >= 0)
{
if (fpattern_submatch(pat, fname+i))
{
return (TRUE);
}
i--;
}
return (FALSE);
case SUB:
/* Match zero or more chars */
i = 0;
while (fname[i] != '\0' &&
#if DELIM
fname[i] != DEL && fname[i] != DEL2 &&
#endif
fname[i] != '.')
i++;
while (i >= 0)
{
if (fpattern_submatch(pat, fname+i))
return (TRUE);
i--;
}
return (FALSE);
case QUOTE:
/* Match a quoted char */
pch = *pat;
if (lowercase(fch) != lowercase(pch) || pch == '\0')
return (FALSE);
fname++;
pat++;
break;
case FPAT_SET_L:
/* Match char set/range */
yes = TRUE;
if (*pat == FPAT_SET_NOT)
{
pat++;
yes = FALSE; /* Set negation */
}
/* Look for [s], [-], [abc], [a-c] */
match = !yes;
while (*pat != FPAT_SET_R && *pat != '\0')
{
if (*pat == QUOTE)
pat++; /* Quoted char */
if (*pat == '\0')
break;
lo = *pat++;
hi = lo;
if (*pat == FPAT_SET_THRU)
{
/* Range */
pat++;
if (*pat == QUOTE)
pat++; /* Quoted char */
if (*pat == '\0')
break;
hi = *pat++;
}
if (*pat == '\0')
break;
/* Compare character to set range */
if (lowercase(fch) >= lowercase(lo) &&
lowercase(fch) <= lowercase(hi))
match = yes;
}
if (!match)
{
return (FALSE);
}
if (*pat == '\0')
return (FALSE); /* Missing closing bracket */
fname++;
pat++;
break;
case FPAT_NOT:
/* Match only if rest of pattern does not match */
if (*pat == '\0')
return (FALSE); /* Missing subpattern */
i = fpattern_submatch(pat, fname);
return !i;
#if DELIM
case DEL:
#if DEL2 != DEL
case DEL2:
#endif
/* Match path delimiter char */
if (fch != DEL && fch != DEL2)
return (FALSE);
fname++;
break;
#endif
default:
/* Match a (non-null) char exactly */
if (lowercase(fch) != lowercase(pch))
{
return (FALSE);
}
fname++;
break;
}
}
/* Check for complete match */
if (*fname != '\0')
return (FALSE);
/* Successful match */
return (TRUE);
}
/*---------------------------------------------------------------------
* fpattern_match()
* Attempts to match pattern 'pat' to filename 'fname'.
*
* Returns
* 1 (true) if the filename matches, otherwise 0 (false).
*
* Caveats
* If 'fname' is null, zero (false) is returned.
*
* If 'pat' is null, zero (false) is returned.
*
* If 'pat' is empty (""), the only filename it matches is the
* empty string ("").
*
* If 'fname' is empty, the only pattern that will match it is
* the empty string ("").
*
* If 'pat' is not a well-formed pattern, zero (false) is
* returned.
*
* Upper and lower case letters are treated the same; alphabetic
* characters are converted to lower case before matching occurs.
* Conversion to lower case is dependent upon the current locale
* setting.
*/
int fpattern_match(const char *pat, const char *fname)
{
int rc;
/* Check args */
if (fname == NULL)
return (FALSE);
if (pat == NULL)
return (FALSE);
/* Verify that the pattern is valid, and get its length */
if (!fpattern_isvalid(pat))
return (FALSE);
/* Attempt to match pattern against filename */
if (fname[0] == '\0')
return (pat[0] == '\0'); /* Special case */
rc = fpattern_submatch(pat, fname);
}
/* End of File */