xref: /csrg-svn/lib/libc/gen/fnmatch.c (revision 39734)
1*39734Sbostic /*
2*39734Sbostic  * Copyright (c) 1989 The Regents of the University of California.
3*39734Sbostic  * All rights reserved.
4*39734Sbostic  *
5*39734Sbostic  * This code is derived from software contributed to Berkeley by
6*39734Sbostic  * Guido van Rossum.
7*39734Sbostic  *
8*39734Sbostic  * Redistribution and use in source and binary forms are permitted
9*39734Sbostic  * provided that the above copyright notice and this paragraph are
10*39734Sbostic  * duplicated in all such forms and that any documentation,
11*39734Sbostic  * advertising materials, and other materials related to such
12*39734Sbostic  * distribution and use acknowledge that the software was developed
13*39734Sbostic  * by the University of California, Berkeley.  The name of the
14*39734Sbostic  * University may not be used to endorse or promote products derived
15*39734Sbostic  * from this software without specific prior written permission.
16*39734Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17*39734Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18*39734Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19*39734Sbostic  */
20*39734Sbostic 
21*39734Sbostic #if defined(LIBC_SCCS) && !defined(lint)
22*39734Sbostic static char sccsid[] = "@(#)fnmatch.c	5.1 (Berkeley) 12/19/89";
23*39734Sbostic #endif /* LIBC_SCCS and not lint */
24*39734Sbostic 
25*39734Sbostic /*
26*39734Sbostic  * Function fnmatch() as proposed in Posix 1003.2 B.6 (rev. 9).
27*39734Sbostic  * Compares a filename or pathname to a pattern.
28*39734Sbostic  */
29*39734Sbostic 
30*39734Sbostic #include <unistd.h>
31*39734Sbostic #include <string.h>
32*39734Sbostic 
33*39734Sbostic #define	EOS	'\0'
34*39734Sbostic 
35*39734Sbostic fnmatch(pattern, string, flags)
36*39734Sbostic 	register char *pattern, *string;
37*39734Sbostic 	int flags;
38*39734Sbostic {
39*39734Sbostic 	register char c;
40*39734Sbostic 	char test, *rangematch();
41*39734Sbostic 
42*39734Sbostic 	for (;;)
43*39734Sbostic 		switch (c = *pattern++) {
44*39734Sbostic 		case EOS:
45*39734Sbostic 			return(*string == EOS);
46*39734Sbostic 		case '?':
47*39734Sbostic 			if ((test = *string++) == EOS ||
48*39734Sbostic 			    test == '/' && flags & FNM_PATHNAME)
49*39734Sbostic 				return(0);
50*39734Sbostic 			break;
51*39734Sbostic 		case '*':
52*39734Sbostic 			c = *pattern;
53*39734Sbostic 			/* collapse multiple stars */
54*39734Sbostic 			while (c == '*')
55*39734Sbostic 				c = *++pattern;
56*39734Sbostic 
57*39734Sbostic 			/* optimize for pattern with * at end or before / */
58*39734Sbostic 			if (c == EOS)
59*39734Sbostic 				if (flags & FNM_PATHNAME)
60*39734Sbostic 					return(!index(string, '/'));
61*39734Sbostic 				else
62*39734Sbostic 					return(1);
63*39734Sbostic 			else if (c == '/' && flags & FNM_PATHNAME) {
64*39734Sbostic 				if ((string = index(string, '/')) == NULL)
65*39734Sbostic 					return(0);
66*39734Sbostic 				break;
67*39734Sbostic 			}
68*39734Sbostic 
69*39734Sbostic 			/* general case, use recursion */
70*39734Sbostic 			while ((test = *string) != EOS) {
71*39734Sbostic 				if (fnmatch(pattern, string, flags))
72*39734Sbostic 					return(1);
73*39734Sbostic 				if (test == '/' && flags & FNM_PATHNAME)
74*39734Sbostic 					break;
75*39734Sbostic 				++string;
76*39734Sbostic 			}
77*39734Sbostic 			return(0);
78*39734Sbostic 		case '[':
79*39734Sbostic 			if ((test = *string++) == EOS ||
80*39734Sbostic 			    test == '/' && flags & FNM_PATHNAME)
81*39734Sbostic 				return(0);
82*39734Sbostic 			if ((pattern = rangematch(pattern, test)) == NULL)
83*39734Sbostic 				return(0);
84*39734Sbostic 			break;
85*39734Sbostic 		case '\\':
86*39734Sbostic 			if (flags & FNM_QUOTE) {
87*39734Sbostic 				if ((c = *pattern++) == EOS) {
88*39734Sbostic 					c = '\\';
89*39734Sbostic 					--pattern;
90*39734Sbostic 				}
91*39734Sbostic 				if (c != *string++)
92*39734Sbostic 					return(0);
93*39734Sbostic 				break;
94*39734Sbostic 			}
95*39734Sbostic 			/* FALLTHROUGH */
96*39734Sbostic 		default:
97*39734Sbostic 			if (c != *string++)
98*39734Sbostic 				return(0);
99*39734Sbostic 			break;
100*39734Sbostic 		}
101*39734Sbostic }
102*39734Sbostic 
103*39734Sbostic static char *
104*39734Sbostic rangematch(pattern, test)
105*39734Sbostic 	register char *pattern, test;
106*39734Sbostic {
107*39734Sbostic 	register char c, c2;
108*39734Sbostic 	int negate, ok;
109*39734Sbostic 
110*39734Sbostic 	if (negate = (*pattern == '!'))
111*39734Sbostic 		++pattern;
112*39734Sbostic 
113*39734Sbostic 	/*
114*39734Sbostic 	 * TO DO: quoting
115*39734Sbostic 	 */
116*39734Sbostic 
117*39734Sbostic 	for (ok = 0; (c = *pattern++) != ']';) {
118*39734Sbostic 		if (c == EOS)
119*39734Sbostic 			return(NULL);		/* illegal pattern */
120*39734Sbostic 		if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') {
121*39734Sbostic 			if (c <= test && test <= c2)
122*39734Sbostic 				ok = 1;
123*39734Sbostic 			pattern += 2;
124*39734Sbostic 		}
125*39734Sbostic 		else if (c == test)
126*39734Sbostic 			ok = 1;
127*39734Sbostic 	}
128*39734Sbostic 	return(ok == negate ? NULL : pattern);
129*39734Sbostic }
130