/* REG.C -- pattern matching functions int matches(char *wildcarded_string, char *test_string) does a full test to see if test_string matches with wildcarded_string; returns 0 if the match failed, otherwise a number indicating how well the string matched (a higher number means a better match) int wild_match(char *wildcarded_string, char *test_string) tries to short-cut the matching process if possible, meaning that if the strings don't match, this function will be MUCH quicker than the one above; same return values as above both functions are case INsensitive this is an edited/enhanced version of the pattern matcher posted to the IRC operator's mailing list sometime in early 1994, and possibly later implemented into the IRC server code as far as I know, this is free-use code; enjoy */ #include #include #define tolower(c) ((((c)>='A') && ((c)<='Z')) ? ((c)-'A'+'a') : c) /* ** matches() ** Iterative matching function, rather than recursive. ** Written by Douglas A Lewis (dalewis@acsu.buffalo.edu) ** edited by Robey Pointer (robey@wc130.residence.gatech.edu) */ int matches(ma, na) char *ma, *na; { int wild=0, q=0, close=0; unsigned char *m=(unsigned char *)ma, *n=(unsigned char *)na; unsigned char *mask=(unsigned char *)ma; while (1) { if (!*m) { if (!*n) return close+1; for (m--; (*m == '?') && (m>mask); m--) ; if ((*m == '*') && (m>mask) && (m[-1]!='\\')) return close+1; if (wild) { m=(unsigned char *)ma; n=(unsigned char *)++na; } else return 0; } else if (!*n) { while (*m == '*') m++; return (*m == 0) ? close+1 : 0; } if (*m == '*') { while (*m == '*') m++; wild=1; ma=(char *)m; na=(char *)n; } if (*m == '\\') { m++; q=1; } else q=0; if ((tolower(*m) != tolower(*n)) && ((*m != '?') || q)) { if (wild) { m=(unsigned char *)ma; n=(unsigned char *)++na; } else return 0; } else { if ((*m!='?') || q) close++; if (*m) m++; if (*n) n++; } } } /* this is a wrapper function for matches, to speed things up for matches where the last few characters are the most important (IE HOSTMASKS). it starts at the end of each string and works backward until the first wildcard '*'. if it finds an unmatched character, it returns immediate- ly. so, for an extreme example, a match of "*!goshguys@*clemson.edu" for "Robey!goshguys@eng.clemson.com" will fail almost instantaneously (the final 'u' != the final 'm'). i hope this speeds up matching. i really do. :) thanks to justin slootsky, who basically came up with the whole concept (in slightly more complex form). i tried to put lots of comments, cos string matching is not my thing, and i had to sit and think for 5 minutes for every line. (ugh!) */ int wild_match(ma,na) unsigned char *ma, *na; { unsigned char *m=ma, *n=na; int close=0; /* take care of null strings (should never match) */ if ((ma==(unsigned char *)0) || (na==(unsigned char *)0)) return 0; if ((!*ma) || (!*na)) return 0; /* find the end of each string */ while (*m) m++; while (*n) n++; m--; n--; /* check the match backwards */ /* while: chars are identical OR the mask char is an unquoted '?' & haven't reached the start of either string & mask char isn't an unquoted '*' */ while (((tolower(*m) == tolower(*n)) || ((*m == '?') && (m[-1]!='\\'))) && (m!=ma) && (n!=na) && !((*m == '*') && (m[-1]!='\\'))) { if (!((*m == '?') && (m[-1]!='\\'))) close++; /* 1 more exact match */ m--; n--; if (*m == '\\') m--; /* if mask was quoting something, skip the \ */ } /* case I - hit an unquoted '*' in mask string (call matches()) */ if ((*m == '*') && (m[-1]!='\\')) return matches(ma,na); /* case II - entire string matched, there were no '*' */ if ((m==ma) && (n==na) && (tolower(*m) == tolower(*n))) return close+1; /* case III - one of the strings ended prematurely (no match) */ if ((m==ma) || (n==na)) return 0; /* case IV - failed to match the ending strings, so abort */ return 0; }