+
+#define MATCH_MAX_CALLS 512 /* ACK! This dies when it's less that this
+ and we have long lines to parse */
+/** Check a string against a mask.
+ * This test checks using extended wildcards: '*' means match zero
+ * or more characters of any type; '?' means match exactly one
+ * character of any type; '#' means match exactly one character that
+ * is a number; '@' means match exactly one character that is a
+ * letter; '\s' means match a space.
+ *
+ * This function supports escaping, so that a wildcard may be matched
+ * exactly.
+ *
+ * @param[in] mask Wildcard-containing mask.
+ * @param[in] name String to check against \a mask.
+ * @return Zero if \a mask matches \a name, non-zero if no match.
+ */
+int
+match_esc(const char *mask, const char *name)
+{
+ const unsigned char *m = (const unsigned char *)mask;
+ const unsigned char *n = (const unsigned char *)name;
+ const unsigned char *ma = (const unsigned char *)mask;
+ const unsigned char *na = (const unsigned char *)name;
+ int wild = 0;
+ int calls = 0;
+ int quote = 0;
+ int match1 = 0;
+
+ s_assert(mask != NULL);
+ s_assert(name != NULL);
+
+ if(!mask || !name)
+ return 0;
+
+ /* if the mask is "*", it matches everything */
+ if((*m == '*') && (*(m + 1) == '\0'))
+ return 1;
+
+ while(calls++ < MATCH_MAX_CALLS)
+ {
+ if(quote)
+ quote++;
+ if(quote == 3)
+ quote = 0;
+ if(*m == '\\' && !quote)
+ {
+ m++;
+ quote = 1;
+ continue;
+ }
+ if(!quote && *m == '*')
+ {
+ /*
+ * XXX - shouldn't need to spin here, the mask should have been
+ * collapsed before match is called
+ */
+ while(*m == '*')
+ m++;
+
+ wild = 1;
+ ma = m;
+ na = n;
+
+ if(*m == '\\')
+ {
+ m++;
+ /* This means it is an invalid mask -A1kmm. */
+ if(!*m)
+ return 0;
+ quote++;
+ continue;
+ }
+ }
+
+ if(!*m)
+ {
+ if(!*n)
+ return 1;
+ if(quote)
+ return 0;
+ for(m--; (m > (const unsigned char *)mask) && (*m == '?'); m--);;
+
+ if(*m == '*' && (m > (const unsigned char *)mask))
+ return 1;
+ if(!wild)
+ return 0;
+ m = ma;
+ n = ++na;
+ }
+ else if(!*n)
+ {
+ /*
+ * XXX - shouldn't need to spin here, the mask should have been
+ * collapsed before match is called
+ */
+ if(quote)
+ return 0;
+ while(*m == '*')
+ m++;
+ return (*m == 0);
+ }
+
+ if(quote)
+ match1 = *m == 's' ? *n == ' ' : ToLower(*m) == ToLower(*n);
+ else if(*m == '?')
+ match1 = 1;
+ else if(*m == '@')
+ match1 = IsLetter(*n);
+ else if(*m == '#')
+ match1 = IsDigit(*n);
+ else
+ match1 = ToLower(*m) == ToLower(*n);
+ if(match1)
+ {
+ if(*m)
+ m++;
+ if(*n)
+ n++;
+ }
+ else
+ {
+ if(!wild)
+ return 0;
+ m = ma;
+ n = ++na;
+ }
+ }
+ return 0;
+}
+