xref: /csrg-svn/lib/libc/gen/fnmatch.c (revision 61111)
139734Sbostic /*
2*61111Sbostic  * Copyright (c) 1989, 1993
3*61111Sbostic  *	The Regents of the University of California.  All rights reserved.
439734Sbostic  *
539734Sbostic  * This code is derived from software contributed to Berkeley by
639734Sbostic  * Guido van Rossum.
739734Sbostic  *
842624Sbostic  * %sccs.include.redist.c%
939734Sbostic  */
1039734Sbostic 
1139734Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*61111Sbostic static char sccsid[] = "@(#)fnmatch.c	8.1 (Berkeley) 06/04/93";
1339734Sbostic #endif /* LIBC_SCCS and not lint */
1439734Sbostic 
1539734Sbostic /*
1654535Sbostic  * Function fnmatch() as proposed in POSIX 1003.2 B.6 (D11.2).
1739734Sbostic  * Compares a filename or pathname to a pattern.
1839734Sbostic  */
1939734Sbostic 
2054534Sbostic #include <fnmatch.h>
2139734Sbostic #include <string.h>
2239734Sbostic 
2339734Sbostic #define	EOS	'\0'
2439734Sbostic 
2554535Sbostic static const char *rangematch __P((const char *, int));
2643528Sbostic 
2739734Sbostic fnmatch(pattern, string, flags)
2854534Sbostic 	register const char *pattern, *string;
2939734Sbostic 	int flags;
3039734Sbostic {
3139734Sbostic 	register char c;
3254534Sbostic 	char test;
3339734Sbostic 
3439734Sbostic 	for (;;)
3539734Sbostic 		switch (c = *pattern++) {
3639734Sbostic 		case EOS:
3754534Sbostic 			return (*string == EOS ? 0 : FNM_NOMATCH);
3839734Sbostic 		case '?':
3939734Sbostic 			if ((test = *string++) == EOS ||
4039734Sbostic 			    test == '/' && flags & FNM_PATHNAME)
4154534Sbostic 				return (FNM_NOMATCH);
4239734Sbostic 			break;
4339734Sbostic 		case '*':
4439734Sbostic 			c = *pattern;
4554534Sbostic 			/* Collapse multiple stars. */
4639734Sbostic 			while (c == '*')
4739734Sbostic 				c = *++pattern;
4839734Sbostic 
4954534Sbostic 			/* Optimize for pattern with * at end or before /. */
5039734Sbostic 			if (c == EOS)
5139734Sbostic 				if (flags & FNM_PATHNAME)
5254534Sbostic 					return (index(string, '/') == NULL ?
5354534Sbostic 					    0 : FNM_NOMATCH);
5439734Sbostic 				else
5554534Sbostic 					return (0);
5639734Sbostic 			else if (c == '/' && flags & FNM_PATHNAME) {
5739734Sbostic 				if ((string = index(string, '/')) == NULL)
5854534Sbostic 					return (FNM_NOMATCH);
5939734Sbostic 				break;
6039734Sbostic 			}
6139734Sbostic 
6254534Sbostic 			/* General case, use recursion. */
6339734Sbostic 			while ((test = *string) != EOS) {
6454534Sbostic 				if (!fnmatch(pattern, string, flags))
6554534Sbostic 					return (0);
6639734Sbostic 				if (test == '/' && flags & FNM_PATHNAME)
6739734Sbostic 					break;
6839734Sbostic 				++string;
6939734Sbostic 			}
7054534Sbostic 			return (FNM_NOMATCH);
7139734Sbostic 		case '[':
7239734Sbostic 			if ((test = *string++) == EOS ||
7339734Sbostic 			    test == '/' && flags & FNM_PATHNAME)
7454534Sbostic 				return (FNM_NOMATCH);
7539734Sbostic 			if ((pattern = rangematch(pattern, test)) == NULL)
7654534Sbostic 				return (FNM_NOMATCH);
7739734Sbostic 			break;
7839734Sbostic 		case '\\':
7954534Sbostic 			if (!(flags & FNM_NOESCAPE)) {
8039734Sbostic 				if ((c = *pattern++) == EOS) {
8139734Sbostic 					c = '\\';
8239734Sbostic 					--pattern;
8339734Sbostic 				}
8439734Sbostic 				if (c != *string++)
8554534Sbostic 					return (FNM_NOMATCH);
8639734Sbostic 				break;
8739734Sbostic 			}
8839734Sbostic 			/* FALLTHROUGH */
8939734Sbostic 		default:
9039734Sbostic 			if (c != *string++)
9154534Sbostic 				return (FNM_NOMATCH);
9239734Sbostic 			break;
9339734Sbostic 		}
9454534Sbostic 	/* NOTREACHED */
9539734Sbostic }
9654534Sbostic 
9754535Sbostic static const char *
9854534Sbostic rangematch(pattern, test)
9954535Sbostic 	register const char *pattern;
10054534Sbostic 	register int test;
10154534Sbostic {
10254534Sbostic 	register char c, c2;
10354534Sbostic 	int negate, ok;
10454534Sbostic 
10554534Sbostic 	if (negate = (*pattern == '!'))
10654534Sbostic 		++pattern;
10754534Sbostic 
10854534Sbostic 	/*
10954534Sbostic 	 * XXX
11054534Sbostic 	 * TO DO: quoting
11154534Sbostic 	 */
11254534Sbostic 	for (ok = 0; (c = *pattern++) != ']';) {
11354534Sbostic 		if (c == EOS)
11454534Sbostic 			return (NULL);		/* Illegal pattern. */
11554534Sbostic 		if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') {
11654534Sbostic 			if (c <= test && test <= c2)
11754534Sbostic 				ok = 1;
11854534Sbostic 			pattern += 2;
11954534Sbostic 		}
12054534Sbostic 		else if (c == test)
12154534Sbostic 			ok = 1;
12254534Sbostic 	}
12354534Sbostic 	return (ok == negate ? NULL : pattern);
12454534Sbostic }
125