#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 */