/* -*-c-*-
*
- * $Id: wildcard.c,v 1.1 2001/02/04 17:14:42 mdw Exp $
- *
* Matches wildcard patterns
*
* (c) 2001 Mark Wooding
*/
-/*----- Licensing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
*
* This file is part of Anag: a simple wordgame helper.
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* Anag is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with Anag; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/*----- Revision history --------------------------------------------------*
- *
- * $Log: wildcard.c,v $
- * Revision 1.1 2001/02/04 17:14:42 mdw
- * Initial checkin
- *
- */
-
/*----- Header files ------------------------------------------------------*/
#include "anag.h"
static int match(const char *p, const char *s)
{
- for (;;) {
- char pch = *p++, pche, sch;
- int sense;
+ char pch, pche, sch;
+ int sense;
+ for (;;) {
+ pch = *p++;
switch (pch) {
+
case '?':
- if (!*s)
- return (0);
- s++;
+ /* If there's no character left, then we fail; otherwise consume
+ * anything and move on.
+ */
+
+ if (!*s++) return (0);
break;
+
case '*':
- if (!*p)
- return (1);
- while (*s) {
- if (match(p, s))
- return (1);
+ /* If there's no more pattern then we win. */
+ if (!*p) return (1);
+
+ /* Try skipping any number of characters from the pattern looking for
+ * a match.
+ */
+ do {
+ if (match(p, s)) return (1);
s++;
- }
+ } while (*s);
return (0);
+
case '[':
- if (!*s)
- return (0);
+ /* Character sets. This is the hard part. */
+
+ /* If there is no character left, then we fail. */
+ if (!*s) return (0);
+
+ /* Fetch the string character, and start munching through the
+ * pattern.
+ */
sch = *s++;
- pch = *p++;
- sense = 1;
- if (pch == '^' || pch == '!') {
- sense = !sense;
- pch = *p++;
- }
+ pch = *p++; sense = 1;
+
+ /* Maybe we need to negate. */
+ if (pch == '^' || pch == '!') { sense = !sense; pch = *p++; }
+
+ /* A close bracket here is literal. Watch for ranges. */
if (pch == ']') {
if (*p == '-' && p[1] && p[1] != ']') {
- pche = p[1];
- p += 2;
- if (pch <= sch && sch <= pche)
- goto class_match;
- } else if (pch == sch)
- goto class_match;
+ pche = p[1]; p += 2;
+ if (pch <= sch && sch <= pche) goto class_match;
+ } else if (pch == sch) goto class_match;
pch = *p++;
}
+
+ /* Work through the other characters and ranges in the set. */
for (;; pch = *p++) {
- if (!pch || pch == ']')
- goto class_nomatch;
+ if (!pch || pch == ']') goto class_nomatch;
if (*p == '-' && p[1] && p[1] != ']') {
- pche = p[1];
- p += 2;
- if (pch <= sch && sch <= pche)
- goto class_match;
- } else if (pch == sch)
- goto class_match;
+ pche = p[1]; p += 2;
+ if (pch <= sch && sch <= pche) goto class_match;
+ } else if (pch == sch) goto class_match;
}
+
class_match:
- if (!sense)
- return (0);
+ /* Found a match. Chew through the rest of the pattern. */
+ if (!sense) return (0);
for (;;) {
- pch = *p++;
- if (!pch)
- return (0);
- if (pch == ']')
- break;
- if (*p == '-' && p[1] && p[1] != ']')
- p += 2;
+ pch = *p++; if (!pch) return (0);
+ if (pch == ']') break;
+ if (*p == '-' && p[1] && p[1] != ']') p += 2;
}
break;
+
class_nomatch:
- if (sense)
- return (0);
+ /* Found the end of the set, so it's a mismatch. */
+ if (sense) return (0);
break;
+
case '\\':
+ /* Treat the next thing literally. */
pch = *p++;
+ /* fall through... */
+
default:
- if (pch != *s)
- return (0);
- if (!pch)
- return (1);
- s++;
+ /* A plain character match.
+ *
+ * Trick: If this is the end of the pattern, we expect the end of
+ * the string.
+ */
+
+ if (pch != *s++) return (0);
+ if (!pch) return (1);
break;
}
}