xref: /csrg-svn/lib/libc/gen/fnmatch.c (revision 43528)
139734Sbostic /*
239734Sbostic  * Copyright (c) 1989 The Regents of the University of California.
339734Sbostic  * 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*43528Sbostic static char sccsid[] = "@(#)fnmatch.c	5.3 (Berkeley) 06/23/90";
1339734Sbostic #endif /* LIBC_SCCS and not lint */
1439734Sbostic 
1539734Sbostic /*
1639734Sbostic  * Function fnmatch() as proposed in Posix 1003.2 B.6 (rev. 9).
1739734Sbostic  * Compares a filename or pathname to a pattern.
1839734Sbostic  */
1939734Sbostic 
2039734Sbostic #include <unistd.h>
2139734Sbostic #include <string.h>
2239734Sbostic 
2339734Sbostic #define	EOS	'\0'
2439734Sbostic 
25*43528Sbostic static char *
26*43528Sbostic rangematch(pattern, test)
27*43528Sbostic 	register char *pattern, test;
28*43528Sbostic {
29*43528Sbostic 	register char c, c2;
30*43528Sbostic 	int negate, ok;
31*43528Sbostic 
32*43528Sbostic 	if (negate = (*pattern == '!'))
33*43528Sbostic 		++pattern;
34*43528Sbostic 
35*43528Sbostic 	/*
36*43528Sbostic 	 * TO DO: quoting
37*43528Sbostic 	 */
38*43528Sbostic 
39*43528Sbostic 	for (ok = 0; (c = *pattern++) != ']';) {
40*43528Sbostic 		if (c == EOS)
41*43528Sbostic 			return(NULL);		/* illegal pattern */
42*43528Sbostic 		if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') {
43*43528Sbostic 			if (c <= test && test <= c2)
44*43528Sbostic 				ok = 1;
45*43528Sbostic 			pattern += 2;
46*43528Sbostic 		}
47*43528Sbostic 		else if (c == test)
48*43528Sbostic 			ok = 1;
49*43528Sbostic 	}
50*43528Sbostic 	return(ok == negate ? NULL : pattern);
51*43528Sbostic }
52*43528Sbostic 
5339734Sbostic fnmatch(pattern, string, flags)
5439734Sbostic 	register char *pattern, *string;
5539734Sbostic 	int flags;
5639734Sbostic {
5739734Sbostic 	register char c;
5839734Sbostic 	char test, *rangematch();
5939734Sbostic 
6039734Sbostic 	for (;;)
6139734Sbostic 		switch (c = *pattern++) {
6239734Sbostic 		case EOS:
6339734Sbostic 			return(*string == EOS);
6439734Sbostic 		case '?':
6539734Sbostic 			if ((test = *string++) == EOS ||
6639734Sbostic 			    test == '/' && flags & FNM_PATHNAME)
6739734Sbostic 				return(0);
6839734Sbostic 			break;
6939734Sbostic 		case '*':
7039734Sbostic 			c = *pattern;
7139734Sbostic 			/* collapse multiple stars */
7239734Sbostic 			while (c == '*')
7339734Sbostic 				c = *++pattern;
7439734Sbostic 
7539734Sbostic 			/* optimize for pattern with * at end or before / */
7639734Sbostic 			if (c == EOS)
7739734Sbostic 				if (flags & FNM_PATHNAME)
7839734Sbostic 					return(!index(string, '/'));
7939734Sbostic 				else
8039734Sbostic 					return(1);
8139734Sbostic 			else if (c == '/' && flags & FNM_PATHNAME) {
8239734Sbostic 				if ((string = index(string, '/')) == NULL)
8339734Sbostic 					return(0);
8439734Sbostic 				break;
8539734Sbostic 			}
8639734Sbostic 
8739734Sbostic 			/* general case, use recursion */
8839734Sbostic 			while ((test = *string) != EOS) {
8939734Sbostic 				if (fnmatch(pattern, string, flags))
9039734Sbostic 					return(1);
9139734Sbostic 				if (test == '/' && flags & FNM_PATHNAME)
9239734Sbostic 					break;
9339734Sbostic 				++string;
9439734Sbostic 			}
9539734Sbostic 			return(0);
9639734Sbostic 		case '[':
9739734Sbostic 			if ((test = *string++) == EOS ||
9839734Sbostic 			    test == '/' && flags & FNM_PATHNAME)
9939734Sbostic 				return(0);
10039734Sbostic 			if ((pattern = rangematch(pattern, test)) == NULL)
10139734Sbostic 				return(0);
10239734Sbostic 			break;
10339734Sbostic 		case '\\':
10439734Sbostic 			if (flags & FNM_QUOTE) {
10539734Sbostic 				if ((c = *pattern++) == EOS) {
10639734Sbostic 					c = '\\';
10739734Sbostic 					--pattern;
10839734Sbostic 				}
10939734Sbostic 				if (c != *string++)
11039734Sbostic 					return(0);
11139734Sbostic 				break;
11239734Sbostic 			}
11339734Sbostic 			/* FALLTHROUGH */
11439734Sbostic 		default:
11539734Sbostic 			if (c != *string++)
11639734Sbostic 				return(0);
11739734Sbostic 			break;
11839734Sbostic 		}
11939734Sbostic }
120