xref: /csrg-svn/lib/libc/gen/fnmatch.c (revision 54534)
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*54534Sbostic static char sccsid[] = "@(#)fnmatch.c	5.5 (Berkeley) 06/28/92";
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 
20*54534Sbostic #include <fnmatch.h>
2139734Sbostic #include <string.h>
2239734Sbostic 
2339734Sbostic #define	EOS	'\0'
2439734Sbostic 
25*54534Sbostic static char *rangematch __P((char *, int));
2643528Sbostic 
2739734Sbostic fnmatch(pattern, string, flags)
28*54534Sbostic 	register const char *pattern, *string;
2939734Sbostic 	int flags;
3039734Sbostic {
3139734Sbostic 	register char c;
32*54534Sbostic 	char test;
3339734Sbostic 
3439734Sbostic 	for (;;)
3539734Sbostic 		switch (c = *pattern++) {
3639734Sbostic 		case EOS:
37*54534Sbostic 			return (*string == EOS ? 0 : FNM_NOMATCH);
3839734Sbostic 		case '?':
3939734Sbostic 			if ((test = *string++) == EOS ||
4039734Sbostic 			    test == '/' && flags & FNM_PATHNAME)
41*54534Sbostic 				return (FNM_NOMATCH);
4239734Sbostic 			break;
4339734Sbostic 		case '*':
4439734Sbostic 			c = *pattern;
45*54534Sbostic 			/* Collapse multiple stars. */
4639734Sbostic 			while (c == '*')
4739734Sbostic 				c = *++pattern;
4839734Sbostic 
49*54534Sbostic 			/* Optimize for pattern with * at end or before /. */
5039734Sbostic 			if (c == EOS)
5139734Sbostic 				if (flags & FNM_PATHNAME)
52*54534Sbostic 					return (index(string, '/') == NULL ?
53*54534Sbostic 					    0 : FNM_NOMATCH);
5439734Sbostic 				else
55*54534Sbostic 					return (0);
5639734Sbostic 			else if (c == '/' && flags & FNM_PATHNAME) {
5739734Sbostic 				if ((string = index(string, '/')) == NULL)
58*54534Sbostic 					return (FNM_NOMATCH);
5939734Sbostic 				break;
6039734Sbostic 			}
6139734Sbostic 
62*54534Sbostic 			/* General case, use recursion. */
6339734Sbostic 			while ((test = *string) != EOS) {
64*54534Sbostic 				if (!fnmatch(pattern, string, flags))
65*54534Sbostic 					return (0);
6639734Sbostic 				if (test == '/' && flags & FNM_PATHNAME)
6739734Sbostic 					break;
6839734Sbostic 				++string;
6939734Sbostic 			}
70*54534Sbostic 			return (FNM_NOMATCH);
7139734Sbostic 		case '[':
7239734Sbostic 			if ((test = *string++) == EOS ||
7339734Sbostic 			    test == '/' && flags & FNM_PATHNAME)
74*54534Sbostic 				return (FNM_NOMATCH);
7539734Sbostic 			if ((pattern = rangematch(pattern, test)) == NULL)
76*54534Sbostic 				return (FNM_NOMATCH);
7739734Sbostic 			break;
7839734Sbostic 		case '\\':
79*54534Sbostic 			if (!(flags & FNM_NOESCAPE)) {
8039734Sbostic 				if ((c = *pattern++) == EOS) {
8139734Sbostic 					c = '\\';
8239734Sbostic 					--pattern;
8339734Sbostic 				}
8439734Sbostic 				if (c != *string++)
85*54534Sbostic 					return (FNM_NOMATCH);
8639734Sbostic 				break;
8739734Sbostic 			}
8839734Sbostic 			/* FALLTHROUGH */
8939734Sbostic 		default:
9039734Sbostic 			if (c != *string++)
91*54534Sbostic 				return (FNM_NOMATCH);
9239734Sbostic 			break;
9339734Sbostic 		}
94*54534Sbostic 	/* NOTREACHED */
9539734Sbostic }
96*54534Sbostic 
97*54534Sbostic static char *
98*54534Sbostic rangematch(pattern, test)
99*54534Sbostic 	register char *pattern;
100*54534Sbostic 	register int test;
101*54534Sbostic {
102*54534Sbostic 	register char c, c2;
103*54534Sbostic 	int negate, ok;
104*54534Sbostic 
105*54534Sbostic 	if (negate = (*pattern == '!'))
106*54534Sbostic 		++pattern;
107*54534Sbostic 
108*54534Sbostic 	/*
109*54534Sbostic 	 * XXX
110*54534Sbostic 	 * TO DO: quoting
111*54534Sbostic 	 */
112*54534Sbostic 	for (ok = 0; (c = *pattern++) != ']';) {
113*54534Sbostic 		if (c == EOS)
114*54534Sbostic 			return (NULL);		/* Illegal pattern. */
115*54534Sbostic 		if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') {
116*54534Sbostic 			if (c <= test && test <= c2)
117*54534Sbostic 				ok = 1;
118*54534Sbostic 			pattern += 2;
119*54534Sbostic 		}
120*54534Sbostic 		else if (c == test)
121*54534Sbostic 			ok = 1;
122*54534Sbostic 	}
123*54534Sbostic 	return (ok == negate ? NULL : pattern);
124*54534Sbostic }
125