#include "elm_defs.h"
/*
* patmatch(pat, str, opts) - Very simple pattern matching.
*
* Returns TRUE if the pattern "pat" completely matches
* any portion of the string "str".
*
* Patterns may include the following special characters:
*
* - A '?' matches any single character.
* - A '*' matches zero or more characters.
* - A '^' at the front of the pattern anchors the front.
* - A '$' at the end of the pattern anchors the tail.
* - A '\' suppresses the special meaning of the above characters.
*
* The following options modify the match conditions:
*
* PM_NOCASE Matching of alphabetic chars normally is case-significant.
* When this option is specified, alphabetic characters are
* compared in a case-INsignificant fashion.
*
* PM_WSFOLD When this option is specified, any sequence of one or more
* whitespace characters in the pattern match a sequence of
* any one or more whitespace characters in the target string.
*
* PM_FANCHOR When this option is specified, the pattern is treated as
* if a "^" anchor appeared at the front.
*
* PM_BANCHOR When this option is specified, the pattern is treated as
* if a "$" anchor appeared at the back.
*
* That's it. No [character classes], or other overly fancy stuff.
*/
static int trymatch P_((const char *, const char *, const char *, int));
int patmatch(pat, str, opts)
const char *pat, *str;
int opts;
{
int len;
const char *pstop;
if (pat[0] == '^') {
opts |= PM_FANCHOR;
++pat;
}
len = strlen(pat);
if (len > 1 && pat[len-1] == '$' && pat[len-2] != '\\') {
opts |= PM_BANCHOR;
--len;
}
pstop = pat+len;
for ( ; *str != '\0' ; ++str) {
if (trymatch(str, pat, pstop, opts))
return TRUE;
if (opts & PM_FANCHOR)
return FALSE;
}
return FALSE;
}
static int trymatch(str, pat, pstop, opts)
const char *str, *pat, *pstop;
int opts;
{
while (pat < pstop) {
/* handle "*" wildcard */
if (*pat == '*') {
do {
if (++pat >= pstop)
return TRUE;
} while (*pat == '*');
for ( ; *str != '\0' ; ++str) {
if (trymatch(str, pat, pstop, opts))
return TRUE;
}
return FALSE;
}
/* end of string matches nothing but "*" */
if (*str == '\0')
return FALSE;
switch (*pat) {
case '?': /* "?" matches anything */
++str;
++pat;
break;
case ' ': /* whitespace */
case '\t':
case '\n':
case '\r':
if (opts & PM_WSFOLD) {
if (!isspace(*str))
return FALSE;
do {
++pat;
} while (pat < pstop && isspace(*pat));
do {
++str;
} while (*str != '\0' && isspace(*str));
} else {
if (*pat != *str)
return FALSE;
++pat;
++str;
}
break;
case '\\': /* literal character */
if (++pat >= pstop || *pat != *str)
return FALSE;
++pat;
++str;
break;
default: /* character match */
if (opts & PM_NOCASE) {
if (tolower(*pat) != tolower(*str))
return FALSE;
} else {
if (*pat != *str)
return FALSE;
}
++str;
++pat;
break;
}
}
return (*str == '\0' || !(opts & PM_BANCHOR));
}
#ifdef _TEST
main()
{
char pat[256], str[256], ans[256];
int opts;
(void) strcpy(pat, "*");
(void) strcpy(str, "hello world");
opts = 0;
for (;;) {
printf("options [%d] : ", opts);
fflush(stdout);
if (gets(ans) == NULL)
break;
if (ans[0] != '\0')
opts = atoi(ans);
printf("pattern [%s] : ", pat);
fflush(stdout);
if (gets(ans) == NULL)
break;
if (ans[0] != '\0')
(void) strcpy(pat, ans);
printf("string [%s] : ", str);
fflush(stdout);
if (gets(ans) == NULL)
break;
if (ans[0] != '\0')
(void) strcpy(str, ans);
fputs("options =", stdout);
if (opts & PM_NOCASE) fputs(" NOCASE", stdout);
if (opts & PM_WSFOLD) fputs(" WSFOLD", stdout);
if (opts & PM_FANCHOR) fputs(" FANCHOR", stdout);
if (opts & PM_BANCHOR) fputs(" BANCHOR", stdout);
putchar('\n');
printf("patmatch returns %s\n\n",
(patmatch(pat, str, opts) ? "TRUE" : "FALSE"));
}
}
#endif /* _TEST */
syntax highlighted by Code2HTML, v. 0.9.1