xref: /netbsd-src/lib/libc/gen/fnmatch.c (revision 4b30c543a0b21e3ba94f2c569e9a82b4fdb2075f)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Guido van Rossum.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #if defined(LIBC_SCCS) && !defined(lint)
38 /*static char *sccsid = "from: @(#)fnmatch.c	5.6 (Berkeley) 6/28/92";*/
39 static char *rcsid = "$Id: fnmatch.c,v 1.5 1993/08/26 00:44:31 jtc Exp $";
40 #endif /* LIBC_SCCS and not lint */
41 
42 /*
43  * Function fnmatch() as proposed in POSIX 1003.2 B.6 (D11.2).
44  * Compares a filename or pathname to a pattern.
45  */
46 
47 #include <fnmatch.h>
48 #include <string.h>
49 
50 #define	EOS	'\0'
51 
52 static const char *rangematch __P((const char *, int));
53 
54 fnmatch(pattern, string, flags)
55 	register const char *pattern, *string;
56 	int flags;
57 {
58 	register char c;
59 	char test;
60 
61 	for (;;)
62 		switch (c = *pattern++) {
63 		case EOS:
64 			return (*string == EOS ? 0 : FNM_NOMATCH);
65 		case '?':
66 			if ((test = *string++) == EOS ||
67 			    test == '/' && flags & FNM_PATHNAME)
68 				return (FNM_NOMATCH);
69 			break;
70 		case '*':
71 			c = *pattern;
72 			/* Collapse multiple stars. */
73 			while (c == '*')
74 				c = *++pattern;
75 
76 			/* Optimize for pattern with * at end or before /. */
77 			if (c == EOS)
78 				if (flags & FNM_PATHNAME)
79 					return (index(string, '/') == NULL ?
80 					    0 : FNM_NOMATCH);
81 				else
82 					return (0);
83 			else if (c == '/' && flags & FNM_PATHNAME) {
84 				if ((string = index(string, '/')) == NULL)
85 					return (FNM_NOMATCH);
86 				break;
87 			}
88 
89 			/* General case, use recursion. */
90 			while ((test = *string) != EOS) {
91 				if (!fnmatch(pattern, string, flags))
92 					return (0);
93 				if (test == '/' && flags & FNM_PATHNAME)
94 					break;
95 				++string;
96 			}
97 			return (FNM_NOMATCH);
98 		case '[':
99 			if ((test = *string++) == EOS ||
100 			    test == '/' && flags & FNM_PATHNAME)
101 				return (FNM_NOMATCH);
102 			if ((pattern = rangematch(pattern, test)) == NULL)
103 				return (FNM_NOMATCH);
104 			break;
105 		case '\\':
106 			if (!(flags & FNM_NOESCAPE)) {
107 				if ((c = *pattern++) == EOS) {
108 					c = '\\';
109 					--pattern;
110 				}
111 				if (c != *string++)
112 					return (FNM_NOMATCH);
113 				break;
114 			}
115 			/* FALLTHROUGH */
116 		default:
117 			if (c != *string++)
118 				return (FNM_NOMATCH);
119 			break;
120 		}
121 	/* NOTREACHED */
122 }
123 
124 static const char *
125 rangematch(pattern, test)
126 	register const char *pattern;
127 	register int test;
128 {
129 	register char c, c2;
130 	int negate, ok;
131 
132 	if (negate = (*pattern == '!'))
133 		++pattern;
134 
135 	/*
136 	 * XXX
137 	 * TO DO: quoting
138 	 */
139 	for (ok = 0; (c = *pattern++) != ']';) {
140 		if (c == EOS)
141 			return (NULL);		/* Illegal pattern. */
142 		if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') {
143 			if (c <= test && test <= c2)
144 				ok = 1;
145 			pattern += 2;
146 		}
147 		else if (c == test)
148 			ok = 1;
149 	}
150 	return (ok == negate ? NULL : pattern);
151 }
152