xref: /csrg-svn/lib/libc/gen/fnmatch.c (revision 66839)
139734Sbostic /*
2*66839Sbostic  * Copyright (c) 1989, 1993, 1994
361111Sbostic  *	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*66839Sbostic static char sccsid[] = "@(#)fnmatch.c	8.2 (Berkeley) 04/16/94";
1339734Sbostic #endif /* LIBC_SCCS and not lint */
1439734Sbostic 
1539734Sbostic /*
16*66839Sbostic  * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
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 
25*66839Sbostic static const char *rangematch __P((const char *, int, int));
2643528Sbostic 
27*66839Sbostic int
fnmatch(pattern,string,flags)2839734Sbostic fnmatch(pattern, string, flags)
29*66839Sbostic 	const char *pattern, *string;
3039734Sbostic 	int flags;
3139734Sbostic {
32*66839Sbostic 	const char *stringstart;
33*66839Sbostic 	char c, test;
3439734Sbostic 
35*66839Sbostic 	for (stringstart = string;;)
3639734Sbostic 		switch (c = *pattern++) {
3739734Sbostic 		case EOS:
3854534Sbostic 			return (*string == EOS ? 0 : FNM_NOMATCH);
3939734Sbostic 		case '?':
40*66839Sbostic 			if (*string == EOS)
4154534Sbostic 				return (FNM_NOMATCH);
42*66839Sbostic 			if (*string == '/' && (flags & FNM_PATHNAME))
43*66839Sbostic 				return (FNM_NOMATCH);
44*66839Sbostic 			if (*string == '.' && (flags & FNM_PERIOD) &&
45*66839Sbostic 			    (string == stringstart ||
46*66839Sbostic 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
47*66839Sbostic 				return (FNM_NOMATCH);
48*66839Sbostic 			++string;
4939734Sbostic 			break;
5039734Sbostic 		case '*':
5139734Sbostic 			c = *pattern;
5254534Sbostic 			/* Collapse multiple stars. */
5339734Sbostic 			while (c == '*')
5439734Sbostic 				c = *++pattern;
5539734Sbostic 
56*66839Sbostic 			if (*string == '.' && (flags & FNM_PERIOD) &&
57*66839Sbostic 			    (string == stringstart ||
58*66839Sbostic 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
59*66839Sbostic 				return (FNM_NOMATCH);
60*66839Sbostic 
6154534Sbostic 			/* Optimize for pattern with * at end or before /. */
6239734Sbostic 			if (c == EOS)
6339734Sbostic 				if (flags & FNM_PATHNAME)
64*66839Sbostic 					return (strchr(string, '/') == NULL ?
6554534Sbostic 					    0 : FNM_NOMATCH);
6639734Sbostic 				else
6754534Sbostic 					return (0);
6839734Sbostic 			else if (c == '/' && flags & FNM_PATHNAME) {
69*66839Sbostic 				if ((string = strchr(string, '/')) == NULL)
7054534Sbostic 					return (FNM_NOMATCH);
7139734Sbostic 				break;
7239734Sbostic 			}
7339734Sbostic 
7454534Sbostic 			/* General case, use recursion. */
7539734Sbostic 			while ((test = *string) != EOS) {
76*66839Sbostic 				if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
7754534Sbostic 					return (0);
7839734Sbostic 				if (test == '/' && flags & FNM_PATHNAME)
7939734Sbostic 					break;
8039734Sbostic 				++string;
8139734Sbostic 			}
8254534Sbostic 			return (FNM_NOMATCH);
8339734Sbostic 		case '[':
84*66839Sbostic 			if (*string == EOS)
8554534Sbostic 				return (FNM_NOMATCH);
86*66839Sbostic 			if (*string == '/' && flags & FNM_PATHNAME)
8754534Sbostic 				return (FNM_NOMATCH);
88*66839Sbostic 			if ((pattern =
89*66839Sbostic 			    rangematch(pattern, *string, flags)) == NULL)
90*66839Sbostic 				return (FNM_NOMATCH);
91*66839Sbostic 			++string;
9239734Sbostic 			break;
9339734Sbostic 		case '\\':
9454534Sbostic 			if (!(flags & FNM_NOESCAPE)) {
9539734Sbostic 				if ((c = *pattern++) == EOS) {
9639734Sbostic 					c = '\\';
9739734Sbostic 					--pattern;
9839734Sbostic 				}
9939734Sbostic 			}
10039734Sbostic 			/* FALLTHROUGH */
10139734Sbostic 		default:
10239734Sbostic 			if (c != *string++)
10354534Sbostic 				return (FNM_NOMATCH);
10439734Sbostic 			break;
10539734Sbostic 		}
10654534Sbostic 	/* NOTREACHED */
10739734Sbostic }
10854534Sbostic 
10954535Sbostic static const char *
rangematch(pattern,test,flags)110*66839Sbostic rangematch(pattern, test, flags)
111*66839Sbostic 	const char *pattern;
112*66839Sbostic 	int test, flags;
11354534Sbostic {
11454534Sbostic 	int negate, ok;
115*66839Sbostic 	char c, c2;
11654534Sbostic 
11754534Sbostic 	/*
118*66839Sbostic 	 * A bracket expression starting with an unquoted circumflex
119*66839Sbostic 	 * character produces unspecified results (IEEE 1003.2-1992,
120*66839Sbostic 	 * 3.13.2).  This implementation treats it like '!', for
121*66839Sbostic 	 * consistency with the regular expression syntax.
122*66839Sbostic 	 * J.T. Conklin (conklin@ngai.kaleida.com)
12354534Sbostic 	 */
124*66839Sbostic 	if (negate = (*pattern == '!' || *pattern == '^'))
125*66839Sbostic 		++pattern;
126*66839Sbostic 
12754534Sbostic 	for (ok = 0; (c = *pattern++) != ']';) {
128*66839Sbostic 		if (c == '\\' && !(flags & FNM_NOESCAPE))
129*66839Sbostic 			c = *pattern++;
13054534Sbostic 		if (c == EOS)
131*66839Sbostic 			return (NULL);
132*66839Sbostic 		if (*pattern == '-'
133*66839Sbostic 		    && (c2 = *(pattern+1)) != EOS && c2 != ']') {
134*66839Sbostic 			pattern += 2;
135*66839Sbostic 			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
136*66839Sbostic 				c2 = *pattern++;
137*66839Sbostic 			if (c2 == EOS)
138*66839Sbostic 				return (NULL);
13954534Sbostic 			if (c <= test && test <= c2)
14054534Sbostic 				ok = 1;
141*66839Sbostic 		} else if (c == test)
14254534Sbostic 			ok = 1;
14354534Sbostic 	}
14454534Sbostic 	return (ok == negate ? NULL : pattern);
14554534Sbostic }
146