xref: /original-bsd/lib/libc/gen/fnmatch.c (revision 14744ecf)
121aa27c5Sbostic /*
2*14744ecfSbostic  * Copyright (c) 1989, 1993, 1994
3bac379f5Sbostic  *	The Regents of the University of California.  All rights reserved.
421aa27c5Sbostic  *
521aa27c5Sbostic  * This code is derived from software contributed to Berkeley by
621aa27c5Sbostic  * Guido van Rossum.
721aa27c5Sbostic  *
8bcb80f39Sbostic  * %sccs.include.redist.c%
921aa27c5Sbostic  */
1021aa27c5Sbostic 
1121aa27c5Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*14744ecfSbostic static char sccsid[] = "@(#)fnmatch.c	8.2 (Berkeley) 04/16/94";
1321aa27c5Sbostic #endif /* LIBC_SCCS and not lint */
1421aa27c5Sbostic 
1521aa27c5Sbostic /*
16*14744ecfSbostic  * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
1721aa27c5Sbostic  * Compares a filename or pathname to a pattern.
1821aa27c5Sbostic  */
1921aa27c5Sbostic 
20c5d7c245Sbostic #include <fnmatch.h>
2121aa27c5Sbostic #include <string.h>
2221aa27c5Sbostic 
2321aa27c5Sbostic #define	EOS	'\0'
2421aa27c5Sbostic 
25*14744ecfSbostic static const char *rangematch __P((const char *, int, int));
26c5d7c245Sbostic 
27*14744ecfSbostic int
fnmatch(pattern,string,flags)28c5d7c245Sbostic fnmatch(pattern, string, flags)
29*14744ecfSbostic 	const char *pattern, *string;
30c5d7c245Sbostic 	int flags;
31c5d7c245Sbostic {
32*14744ecfSbostic 	const char *stringstart;
33*14744ecfSbostic 	char c, test;
34c5d7c245Sbostic 
35*14744ecfSbostic 	for (stringstart = string;;)
36c5d7c245Sbostic 		switch (c = *pattern++) {
37c5d7c245Sbostic 		case EOS:
38c5d7c245Sbostic 			return (*string == EOS ? 0 : FNM_NOMATCH);
39c5d7c245Sbostic 		case '?':
40*14744ecfSbostic 			if (*string == EOS)
41c5d7c245Sbostic 				return (FNM_NOMATCH);
42*14744ecfSbostic 			if (*string == '/' && (flags & FNM_PATHNAME))
43*14744ecfSbostic 				return (FNM_NOMATCH);
44*14744ecfSbostic 			if (*string == '.' && (flags & FNM_PERIOD) &&
45*14744ecfSbostic 			    (string == stringstart ||
46*14744ecfSbostic 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
47*14744ecfSbostic 				return (FNM_NOMATCH);
48*14744ecfSbostic 			++string;
49c5d7c245Sbostic 			break;
50c5d7c245Sbostic 		case '*':
51c5d7c245Sbostic 			c = *pattern;
52c5d7c245Sbostic 			/* Collapse multiple stars. */
53c5d7c245Sbostic 			while (c == '*')
54c5d7c245Sbostic 				c = *++pattern;
55c5d7c245Sbostic 
56*14744ecfSbostic 			if (*string == '.' && (flags & FNM_PERIOD) &&
57*14744ecfSbostic 			    (string == stringstart ||
58*14744ecfSbostic 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
59*14744ecfSbostic 				return (FNM_NOMATCH);
60*14744ecfSbostic 
61c5d7c245Sbostic 			/* Optimize for pattern with * at end or before /. */
62c5d7c245Sbostic 			if (c == EOS)
63c5d7c245Sbostic 				if (flags & FNM_PATHNAME)
64*14744ecfSbostic 					return (strchr(string, '/') == NULL ?
65c5d7c245Sbostic 					    0 : FNM_NOMATCH);
66c5d7c245Sbostic 				else
67c5d7c245Sbostic 					return (0);
68c5d7c245Sbostic 			else if (c == '/' && flags & FNM_PATHNAME) {
69*14744ecfSbostic 				if ((string = strchr(string, '/')) == NULL)
70c5d7c245Sbostic 					return (FNM_NOMATCH);
71c5d7c245Sbostic 				break;
72c5d7c245Sbostic 			}
73c5d7c245Sbostic 
74c5d7c245Sbostic 			/* General case, use recursion. */
75c5d7c245Sbostic 			while ((test = *string) != EOS) {
76*14744ecfSbostic 				if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
77c5d7c245Sbostic 					return (0);
78c5d7c245Sbostic 				if (test == '/' && flags & FNM_PATHNAME)
79c5d7c245Sbostic 					break;
80c5d7c245Sbostic 				++string;
81c5d7c245Sbostic 			}
82c5d7c245Sbostic 			return (FNM_NOMATCH);
83c5d7c245Sbostic 		case '[':
84*14744ecfSbostic 			if (*string == EOS)
85c5d7c245Sbostic 				return (FNM_NOMATCH);
86*14744ecfSbostic 			if (*string == '/' && flags & FNM_PATHNAME)
87c5d7c245Sbostic 				return (FNM_NOMATCH);
88*14744ecfSbostic 			if ((pattern =
89*14744ecfSbostic 			    rangematch(pattern, *string, flags)) == NULL)
90*14744ecfSbostic 				return (FNM_NOMATCH);
91*14744ecfSbostic 			++string;
92c5d7c245Sbostic 			break;
93c5d7c245Sbostic 		case '\\':
94c5d7c245Sbostic 			if (!(flags & FNM_NOESCAPE)) {
95c5d7c245Sbostic 				if ((c = *pattern++) == EOS) {
96c5d7c245Sbostic 					c = '\\';
97c5d7c245Sbostic 					--pattern;
98c5d7c245Sbostic 				}
99c5d7c245Sbostic 			}
100c5d7c245Sbostic 			/* FALLTHROUGH */
101c5d7c245Sbostic 		default:
102c5d7c245Sbostic 			if (c != *string++)
103c5d7c245Sbostic 				return (FNM_NOMATCH);
104c5d7c245Sbostic 			break;
105c5d7c245Sbostic 		}
106c5d7c245Sbostic 	/* NOTREACHED */
107c5d7c245Sbostic }
108c5d7c245Sbostic 
1091444a3beSbostic static const char *
rangematch(pattern,test,flags)110*14744ecfSbostic rangematch(pattern, test, flags)
111*14744ecfSbostic 	const char *pattern;
112*14744ecfSbostic 	int test, flags;
113a3293107Sbostic {
114a3293107Sbostic 	int negate, ok;
115*14744ecfSbostic 	char c, c2;
116a3293107Sbostic 
117a3293107Sbostic 	/*
118*14744ecfSbostic 	 * A bracket expression starting with an unquoted circumflex
119*14744ecfSbostic 	 * character produces unspecified results (IEEE 1003.2-1992,
120*14744ecfSbostic 	 * 3.13.2).  This implementation treats it like '!', for
121*14744ecfSbostic 	 * consistency with the regular expression syntax.
122*14744ecfSbostic 	 * J.T. Conklin (conklin@ngai.kaleida.com)
123a3293107Sbostic 	 */
124*14744ecfSbostic 	if (negate = (*pattern == '!' || *pattern == '^'))
125*14744ecfSbostic 		++pattern;
126*14744ecfSbostic 
127a3293107Sbostic 	for (ok = 0; (c = *pattern++) != ']';) {
128*14744ecfSbostic 		if (c == '\\' && !(flags & FNM_NOESCAPE))
129*14744ecfSbostic 			c = *pattern++;
130a3293107Sbostic 		if (c == EOS)
131*14744ecfSbostic 			return (NULL);
132*14744ecfSbostic 		if (*pattern == '-'
133*14744ecfSbostic 		    && (c2 = *(pattern+1)) != EOS && c2 != ']') {
134*14744ecfSbostic 			pattern += 2;
135*14744ecfSbostic 			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
136*14744ecfSbostic 				c2 = *pattern++;
137*14744ecfSbostic 			if (c2 == EOS)
138*14744ecfSbostic 				return (NULL);
139a3293107Sbostic 			if (c <= test && test <= c2)
140a3293107Sbostic 				ok = 1;
141*14744ecfSbostic 		} else if (c == test)
142a3293107Sbostic 			ok = 1;
143a3293107Sbostic 	}
144a3293107Sbostic 	return (ok == negate ? NULL : pattern);
145a3293107Sbostic }
146