/*
* match.c
* wildcard matching functions
*
* $Id: match.c,v 1.11 2004-04-06 06:56:38 wcc Exp $
*
* Once this code was working, I added support for % so that I could
* use the same code both in Eggdrop and in my IrcII client.
* Pleased with this, I added the option of a fourth wildcard, ~,
* which matches varying amounts of whitespace (at LEAST one space,
* though, for sanity reasons).
*
* This code would not have been possible without the prior work and
* suggestions of various sourced. Special thanks to Robey for
* all his time/help tracking down bugs and his ever-helpful advice.
*
* 04/09: Fixed the "*\*" against "*a" bug (caused an endless loop)
*
* Chris Fuller (aka Fred1@IRC & Fwitz@IRC)
* crf@cfox.bchs.uh.edu
*
* I hereby release this code into the public domain
*
*/
#include "main.h"
#define QUOTE '\\' /* quoting character (overrides wildcards) */
#define WILDS '*' /* matches 0 or more characters (including spaces) */
#define WILDP '%' /* matches 0 or more non-space characters */
#define WILDQ '?' /* matches ecactly one character */
#define WILDT '~' /* matches 1 or more spaces */
#define NOMATCH 0
#define MATCH (match+sofar)
#define PERMATCH (match+saved+sofar)
int _wild_match_per(register unsigned char *m, register unsigned char *n)
{
unsigned char *ma = m, *lsm = 0, *lsn = 0, *lpm = 0, *lpn = 0;
int match = 1, saved = 0, space;
register unsigned int sofar = 0;
/* null strings should never match */
if ((m == 0) || (n == 0) || (!*n))
return NOMATCH;
while (*n) {
if (*m == WILDT) { /* Match >=1 space */
space = 0; /* Don't need any spaces */
do {
m++;
space++;
} /* Tally 1 more space ... */
while ((*m == WILDT) || (*m == ' ')); /* for each space or ~ */
sofar += space; /* Each counts as exact */
while (*n == ' ') {
n++;
space--;
} /* Do we have enough? */
if (space <= 0)
continue; /* Had enough spaces! */
}
/* Do the fallback */
else {
switch (*m) {
case 0:
do
m--; /* Search backwards */
while ((m > ma) && (*m == '?')); /* For first non-? char */
if ((m > ma) ? ((*m == '*') && (m[-1] != QUOTE)) : (*m == '*'))
return PERMATCH; /* nonquoted * = match */
break;
case WILDP:
while (*(++m) == WILDP); /* Zap redundant %s */
if (*m != WILDS) { /* Don't both if next=* */
if (*n != ' ') { /* WILDS can't match ' ' */
lpm = m;
lpn = n; /* Save '%' fallback spot */
saved += sofar;
sofar = 0; /* And save tally count */
}
continue; /* Done with '%' */
}
/* FALL THROUGH */
case WILDS:
do
m++; /* Zap redundant wilds */
while ((*m == WILDS) || (*m == WILDP));
lsm = m;
lsn = n;
lpm = 0; /* Save '*' fallback spot */
match += (saved + sofar); /* Save tally count */
saved = sofar = 0;
continue; /* Done with '*' */
case WILDQ:
m++;
n++;
continue; /* Match one char */
case QUOTE:
m++; /* Handle quoting */
}
if (rfc_toupper(*m) == rfc_toupper(*n)) { /* If matching */
m++;
n++;
sofar++;
continue; /* Tally the match */
}
#ifdef WILDT
}
#endif
if (lpm) { /* Try to fallback on '%' */
n = ++lpn;
m = lpm;
sofar = 0; /* Restore position */
if ((*n | 32) == 32)
lpm = 0; /* Can't match 0 or ' ' */
continue; /* Next char, please */
}
if (lsm) { /* Try to fallback on '*' */
n = ++lsn;
m = lsm; /* Restore position */
saved = sofar = 0;
continue; /* Next char, please */
}
return NOMATCH; /* No fallbacks=No match */
}
while ((*m == WILDS) || (*m == WILDP))
m++; /* Zap leftover %s & *s */
return (*m) ? NOMATCH : PERMATCH; /* End of both = match */
}
int _wild_match(register unsigned char *m, register unsigned char *n)
{
unsigned char *ma = m, *na = n, *lsm = 0, *lsn = 0;
int match = 1;
register int sofar = 0;
/* null strings should never match */
if ((ma == 0) || (na == 0) || (!*ma) || (!*na))
return NOMATCH;
/* find the end of each string */
while (*(++m));
m--;
while (*(++n));
n--;
while (n >= na) {
/* If the mask runs out of chars before the string, fall back on
* a wildcard or fail. */
if (m < ma) {
if (lsm) {
n = --lsn;
m = lsm;
if (n < na)
lsm = 0;
sofar = 0;
}
else
return NOMATCH;
}
switch (*m) {
case WILDS: /* Matches anything */
do
m--; /* Zap redundant wilds */
while ((m >= ma) && (*m == WILDS));
lsm = m;
lsn = n;
match += sofar;
sofar = 0; /* Update fallback pos */
if (m < ma)
return MATCH;
continue; /* Next char, please */
case WILDQ:
m--;
n--;
continue; /* '?' always matches */
}
if (rfc_toupper(*m) == rfc_toupper(*n)) { /* If matching char */
m--;
n--;
sofar++; /* Tally the match */
continue; /* Next char, please */
}
if (lsm) { /* To to fallback on '*' */
n = --lsn;
m = lsm;
if (n < na)
lsm = 0; /* Rewind to saved pos */
sofar = 0;
continue; /* Next char, please */
}
return NOMATCH; /* No fallback=No match */
}
while ((m >= ma) && (*m == WILDS))
m--; /* Zap leftover %s & *s */
return (m >= ma) ? NOMATCH : MATCH; /* Start of both = match */
}