[alt.sources] Repost: Shell-style wildcard matching

bernie@metapro.DIALix.oz.au (Bernd Felsche) (01/29/91)

[ Sorry to those of you who are seeing this again, but I think this got	]
[ zapped somewhere, on its way to the real world. (no flames or comment)]

Thanks mainly to Rich Salz, we now have a useful shell-style 
wildcard matching routine.  It took a little bashing to make it
behave the same way as the Bourne shell (and Korn shell).

This posting is without the permission of Rich, though I'm sure he
won't mind, as it fixes a few problems that have been unearthed.

Remember, UTSL.

--------------------cut here if you're brave----------------
#!/bin/sh
# manually shar'ed, so don't complain, all right?
# at the end of this shar you should seen the message
# "wildmat.c complete".
#
# Here's shar!
if test -f wildmat.c
then
	echo wildmat.c exists, won\'t clobber.
	exit 1
fi
echo extracting wildmat.c
sed 's/^X//' > wildmat.c << 'SHAR_EOF' &&
X/*
X**  Do shell-style pattern matching for ?, \, [], and * characters.
X**  Might not be robust in face of malformed patterns; e.g., "foo[a-"
X**  could cause a segmentation violation.  It is 8bit clean.
X**
X**  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
X**  Special thanks to Lars Mathiesen for the ABORT code.  This can greatly
X**  speed up failing wildcard patterns.  For example:
X**	pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
X**	text 1:	 -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
X**	text 2:	 -adobe-courier-bold-o-normal--12-120-75-75-p-70-iso8859-1
X**  Text 1 matches with 51 calls, while text 2 fails with 54 calls.  Without
X**  the ABORT, then it takes 22310 calls to fail.  Ugh.
X**
X**  bernie    613-01 91/01/04 19:34 
X**  Fixed problem with terminating * not matching with (null)
X**
X**  bernie    597-00 91/01/08 11:24 
X**  Fixed shell glob negate from '^' to '!'
X**
X**  bernie    597-02 91/01/21 13:43 
X**	Fixed . matching * or ? on first char.
X*/
X
X#define TRUE		1
X#define FALSE		0
X#define ABORT		-1
X
Xstatic int
XStar(s, p)
X    register char	*s;
X    register char	*p;
X{
X    while (DoMatch(s, p) == FALSE) /* gobble up * match */
X	if (*++s == '\0') return ABORT;
X    return TRUE;
X}
X
X
Xstatic int
XDoMatch(s, p)	/* match string "s" to pattern "p" */
X    register char	*s;
X    register char	*p;
X{
X    register int 	 last;
X    register int 	 matched;
X    register int 	 reverse;
X
X    for ( ; *p; s++, p++) { /* parse the string to end */
X
X	if (*s == '\0')
X		return *p == '*' && *++p == '\0' ? TRUE : ABORT;
X
X	switch (*p) { /* parse pattern */
X
X	case '\\':
X	    /* Literal match with following character. */
X	    p++;
X	    /* FALLTHROUGH */
X
X	default: /*literal match*/
X	    if (*s != *p)
X		return FALSE;
X	    continue;
X
X	case '?':
X	    /* Match anything. */
X	    continue;
X
X	case '*':
X	    /* Trailing star matches everything. */
X	    return( *++p ? Star(s, p) : TRUE );
X
X	case '[':
X	    /* [!....] means inverse character class. */
X	    if (reverse = p[1] == '!') p++;
X
X	    for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p)
X		/* This next line requires a good C compiler. */
X		/*     range?		(in bounds)                  (equal) */
X		if ( ( *p == '-' ) ? (*s <= *++p && *s >= last ) : (*s == *p) )
X		    matched = TRUE;
X
X	    if (matched == reverse) return FALSE;
X	    continue;
X
X	}
X    }
X
X    return *s == '\0';
X}
X
X
Xint wildmat(s, p)
X    char	*s;
X    char	*p;
X{
X	if ( (*p == '?' || *p == '*' ) && *s == '.' ) {
X		return FALSE;
X	} else {
X		return DoMatch(s, p) == TRUE;
X	}
X}
SHAR_EOF
chmod 0644 wildmat.c ||
echo extract failed - squezze it yourself!
if test `wc -c < wildmat.c` -ne 2524
then
	echo possible file size error with wildmat.c
	exit 2
fi
echo "wildmat.c complete"

exit	# because you shouldn't execute my signature
-- 
 _--_|\  Bernd Felsche         #include <std/disclaimer.h>
/      \ Metapro Systems, 328 Albany Highway, Victoria Park,  Western Australia
\_.--._/ Fax: +61 9 472 3337   Phone: +61 9 362 9355  TZ=WST-8
      v  E-Mail: bernie@metapro.DIALix.oz.au | bernie@DIALix.oz.au