fnmatch.c revision 1.3 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[] = "@(#)fnmatch.c 5.6 (Berkeley) 6/28/92";
39 #endif /* LIBC_SCCS and not lint */
40
41 /*
42 * Function fnmatch() as proposed in POSIX 1003.2 B.6 (D11.2).
43 * Compares a filename or pathname to a pattern.
44 */
45
46 #include <fnmatch.h>
47 #include <string.h>
48
49 #define EOS '\0'
50
51 static const char *rangematch __P((const char *, int));
52
53 fnmatch(pattern, string, flags)
54 register const char *pattern, *string;
55 int flags;
56 {
57 register char c;
58 char test;
59
60 for (;;)
61 switch (c = *pattern++) {
62 case EOS:
63 return (*string == EOS ? 0 : FNM_NOMATCH);
64 case '?':
65 if ((test = *string++) == EOS ||
66 test == '/' && flags & FNM_PATHNAME)
67 return (FNM_NOMATCH);
68 break;
69 case '*':
70 c = *pattern;
71 /* Collapse multiple stars. */
72 while (c == '*')
73 c = *++pattern;
74
75 /* Optimize for pattern with * at end or before /. */
76 if (c == EOS)
77 if (flags & FNM_PATHNAME)
78 return (index(string, '/') == NULL ?
79 0 : FNM_NOMATCH);
80 else
81 return (0);
82 else if (c == '/' && flags & FNM_PATHNAME) {
83 if ((string = index(string, '/')) == NULL)
84 return (FNM_NOMATCH);
85 break;
86 }
87
88 /* General case, use recursion. */
89 while ((test = *string) != EOS) {
90 if (!fnmatch(pattern, string, flags))
91 return (0);
92 if (test == '/' && flags & FNM_PATHNAME)
93 break;
94 ++string;
95 }
96 return (FNM_NOMATCH);
97 case '[':
98 if ((test = *string++) == EOS ||
99 test == '/' && flags & FNM_PATHNAME)
100 return (FNM_NOMATCH);
101 if ((pattern = rangematch(pattern, test)) == NULL)
102 return (FNM_NOMATCH);
103 break;
104 case '\\':
105 if (!(flags & FNM_NOESCAPE)) {
106 if ((c = *pattern++) == EOS) {
107 c = '\\';
108 --pattern;
109 }
110 if (c != *string++)
111 return (FNM_NOMATCH);
112 break;
113 }
114 /* FALLTHROUGH */
115 default:
116 if (c != *string++)
117 return (FNM_NOMATCH);
118 break;
119 }
120 /* NOTREACHED */
121 }
122
123 static const char *
124 rangematch(pattern, test)
125 register const char *pattern;
126 register int test;
127 {
128 register char c, c2;
129 int negate, ok;
130
131 if (negate = (*pattern == '!'))
132 ++pattern;
133
134 /*
135 * XXX
136 * TO DO: quoting
137 */
138 for (ok = 0; (c = *pattern++) != ']';) {
139 if (c == EOS)
140 return (NULL); /* Illegal pattern. */
141 if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') {
142 if (c <= test && test <= c2)
143 ok = 1;
144 pattern += 2;
145 }
146 else if (c == test)
147 ok = 1;
148 }
149 return (ok == negate ? NULL : pattern);
150 }
151