[comp.unix.shell] PD file-globbing code?

bernie@metapro.DIALix.oz.au (Bernd Felsche) (02/08/91)

In <1991Feb6.081556.25915@parc.xerox.com> janssen@parc.xerox.com (Bill Janssen) writes:

>Anyone have a nice bit of file-globbing code that can be freely used
>by others?  That in csh, sh, ksh, tcsh, and bash doesn't seem to
>qualify...

I recently posted this to alt.sources.something.  It's from Rich Salz's
wildmat routine.  Some problems have been fixed, including the "not"
operator, trailing "*" handling, and a few other bits and pieces.

This is NOT a shell archive.

---------------cut along here with glass cutter---------------
/*
**  Do shell-style pattern matching for ?, \, [], and * characters.
**  Might not be robust in face of malformed patterns; e.g., "foo[a-"
**  could cause a segmentation violation.  It is 8bit clean.
**
**  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
**  Special thanks to Lars Mathiesen for the ABORT code.  This can greatly
**  speed up failing wildcard patterns.  For example:
**	pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
**	text 1:	 -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
**	text 2:	 -adobe-courier-bold-o-normal--12-120-75-75-p-70-iso8859-1
**  Text 1 matches with 51 calls, while text 2 fails with 54 calls.  Without
**  the ABORT, then it takes 22310 calls to fail.  Ugh.
**
**  bernie    613-01 91/01/04 19:34 
**  Fixed problem with terminating * not matching with (null)
**
**  bernie    597-00 91/01/08 11:24 
**  Fixed shell glob negate from '^' to '!'
**
**  bernie    597-02 91/01/21 13:43 
**	Fixed . matching * or ? on first char.
*/

#define TRUE		1
#define FALSE		0
#define ABORT		-1

static int
Star(s, p)
    register char	*s;
    register char	*p;
{
    while (DoMatch(s, p) == FALSE) /* gobble up * match */
	if (*++s == '\0') return ABORT;
    return TRUE;
}


static int
DoMatch(s, p)	/* match string "s" to pattern "p" */
    register char	*s;
    register char	*p;
{
    register int 	 last;
    register int 	 matched;
    register int 	 reverse;

    for ( ; *p; s++, p++) { /* parse the string to end */

	if (*s == '\0')
		return *p == '*' && *++p == '\0' ? TRUE : ABORT;

	switch (*p) { /* parse pattern */

	case '\\':
	    /* Literal match with following character. */
	    p++;
	    /* FALLTHROUGH */

	default: /*literal match*/
	    if (*s != *p)
		return FALSE;
	    continue;

	case '?':
	    /* Match anything. */
	    continue;

	case '*':
	    /* Trailing star matches everything. */
	    return( *++p ? Star(s, p) : TRUE );

	case '[':
	    /* [!....] means inverse character class. */
	    if (reverse = p[1] == '!') p++;

	    for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p)
		/* This next line requires a good C compiler. */
		/*     range?		(in bounds)                  (equal) */
		if ( ( *p == '-' ) ? (*s <= *++p && *s >= last ) : (*s == *p) )
		    matched = TRUE;

	    if (matched == reverse) return FALSE;
	    continue;

	}
    }

    return *s == '\0';
}


int wildmat(s, p)
    char	*s;
    char	*p;
{
	if ( (*p == '?' || *p == '*' ) && *s == '.' ) {
		return FALSE;
	} else {
		return DoMatch(s, p) == TRUE;
	}
}
---------------------the end---------------------------
-- 
 _--_|\  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