/*
 *				p m a t c h . c
 */

/*)LIBRARY
*/

#ifdef	DOCUMENTATION

title	pmatch	Pattern Match -- Unix File Conventions
index		Pattern match -- Unix file conventions

synopsis

	 int
	 pmatch(string, pattern)
	 char	*string;	/* What to look for	*/
	 char	*pattern;	/* Pattern to match	*/

description

	pmatch() returns TRUE if the string argument is matched
	by the pattern argument.  The pattern follows Unix filename
	conventions:
	.lm +8	

 *	matches any (even null) string

 ?	matches any single (non-null) byte

 [class]
	defines a class of characters.  A class consists of either a list
	of valid characters or pairs of characters separated by '-' defining
	a range.

 \	uses the next character literally; same as '\\' at pattern end.

	.lm -8
	Note that upper- and lower-case are distinct.

bugs

author

	Martin Minow, taken from various Unix utilities.

#endif

/*
 *)EDITLEVEL=02
 * Edit History
 * 0.1 09-Dec-81 MM	Initial edit
 */

#define	EOS	0
#define	FALSE	0
#define	TRUE	1

int
pmatch(string, pattern)
char	*string;		/* What to look for			*/
char	*pattern;		/* May have class indicator		*/
/*
 * Recursive routine to match "string" against "pattern".
 * Returns TRUE if successful, FALSE if failure.
 *
 * pattern follows Unix pattern match conventions:
 *	*	matches any (even null) string
 *	?	matches any single (non-null) byte
 *	[class]	defines a class of characters.  A class consists of
 *		either a list of valid characters or pairs of characters
 *		separated by '-' defining a range.
 *	\	uses the next character literally (== '\\' at pattern end).
 * Upper and lower case are distinct.
 */
{
	register int	classchar;	/* Current class character	*/
	register int	stringchar;	/* Current string character	*/
	register int	flag;		/* Class found flag		*/
	int		pattchar;	/* Current pattern character	*/
	int		prevclass;	/* Previous char. for [a-z]	*/

	for (;;++string, ++pattern) {
		stringchar = *string;	/* Initialize -- get string	*/
		switch ((pattchar = *pattern)) {

		case EOS:		/* End of pattern		*/
			return (stringchar == EOS);

		case '*':		/* Always advance		*/
			if (*++pattern == EOS)
				return (TRUE);
			return (match1(string, pattern));

		case '\\':		/* Quote next			*/
			if (pattern[1] != EOS)
				pattchar = *++pattern;

		default:		/* Match exact			*/
			if (stringchar != pattchar)
				return (FALSE);
			break;		/* Advance			*/

		case '?':		/* Match any single byte	*/
			if (stringchar != EOS)
				break;	/* Gotcha, advance		*/
			return (FALSE);

		case '[':		/* Match a class		*/
			prevclass = 32767;	/* Big start now	*/
			flag = 0;		/* No success yet	*/
			while ((classchar = *++pattern) != EOS) {
				switch (classchar) {

				case ']':
					if (flag != FALSE)
						goto classok;
					return (FALSE);

				case '-':
					classchar = pattern[1];
					flag |= (prevclass <= stringchar)
					     && (stringchar <= classchar);
				}
				prevclass = classchar;
				if (stringchar == classchar)
					flag++;
			}
			return (FALSE);
		}
classok:	;
	}
}
		
static int
match1(string, pattern)
register char	*string;
char		*pattern;
/*
 * Advance the string (after '*' in the pattern)
 */
{
	while(*string != EOS) {
		if (pmatch(string, pattern))
			return (TRUE);
		string++;
	}
	return (FALSE);
}
