]> git.saurik.com Git - apple/libc.git/blob - gen.subproj/fnmatch.c
93bb36138119c33d552b6010de1c45c6d2bbe5bf
[apple/libc.git] / gen.subproj / fnmatch.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1989, 1993, 1994
24 * The Regents of the University of California. All rights reserved.
25 *
26 * This code is derived from software contributed to Berkeley by
27 * Guido van Rossum.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58
59 /*
60 * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
61 * Compares a filename or pathname to a pattern.
62 */
63
64 #include <fnmatch.h>
65 #include <string.h>
66
67 #define EOS '\0'
68
69 static const char *rangematch __P((const char *, int, int));
70
71 int
72 fnmatch(pattern, string, flags)
73 const char *pattern, *string;
74 int flags;
75 {
76 const char *stringstart;
77 char c, test;
78
79 for (stringstart = string;;)
80 switch (c = *pattern++) {
81 case EOS:
82 return (*string == EOS ? 0 : FNM_NOMATCH);
83 case '?':
84 if (*string == EOS)
85 return (FNM_NOMATCH);
86 if (*string == '/' && (flags & FNM_PATHNAME))
87 return (FNM_NOMATCH);
88 if (*string == '.' && (flags & FNM_PERIOD) &&
89 (string == stringstart ||
90 ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
91 return (FNM_NOMATCH);
92 ++string;
93 break;
94 case '*':
95 c = *pattern;
96 /* Collapse multiple stars. */
97 while (c == '*')
98 c = *++pattern;
99
100 if (*string == '.' && (flags & FNM_PERIOD) &&
101 (string == stringstart ||
102 ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
103 return (FNM_NOMATCH);
104
105 /* Optimize for pattern with * at end or before /. */
106 if (c == EOS)
107 if (flags & FNM_PATHNAME)
108 return (strchr(string, '/') == NULL ?
109 0 : FNM_NOMATCH);
110 else
111 return (0);
112 else if (c == '/' && flags & FNM_PATHNAME) {
113 if ((string = strchr(string, '/')) == NULL)
114 return (FNM_NOMATCH);
115 break;
116 }
117
118 /* General case, use recursion. */
119 while ((test = *string) != EOS) {
120 if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
121 return (0);
122 if (test == '/' && flags & FNM_PATHNAME)
123 break;
124 ++string;
125 }
126 return (FNM_NOMATCH);
127 case '[':
128 if (*string == EOS)
129 return (FNM_NOMATCH);
130 if (*string == '/' && flags & FNM_PATHNAME)
131 return (FNM_NOMATCH);
132 if ((pattern =
133 rangematch(pattern, *string, flags)) == NULL)
134 return (FNM_NOMATCH);
135 ++string;
136 break;
137 case '\\':
138 if (!(flags & FNM_NOESCAPE)) {
139 if ((c = *pattern++) == EOS) {
140 c = '\\';
141 --pattern;
142 }
143 }
144 /* FALLTHROUGH */
145 default:
146 if (c != *string++)
147 return (FNM_NOMATCH);
148 break;
149 }
150 /* NOTREACHED */
151 }
152
153 static const char *
154 rangematch(pattern, test, flags)
155 const char *pattern;
156 int test, flags;
157 {
158 int negate, ok;
159 char c, c2;
160
161 /*
162 * A bracket expression starting with an unquoted circumflex
163 * character produces unspecified results (IEEE 1003.2-1992,
164 * 3.13.2). This implementation treats it like '!', for
165 * consistency with the regular expression syntax.
166 * J.T. Conklin (conklin@ngai.kaleida.com)
167 */
168 if (negate = (*pattern == '!' || *pattern == '^'))
169 ++pattern;
170
171 for (ok = 0; (c = *pattern++) != ']';) {
172 if (c == '\\' && !(flags & FNM_NOESCAPE))
173 c = *pattern++;
174 if (c == EOS)
175 return (NULL);
176 if (*pattern == '-'
177 && (c2 = *(pattern+1)) != EOS && c2 != ']') {
178 pattern += 2;
179 if (c2 == '\\' && !(flags & FNM_NOESCAPE))
180 c2 = *pattern++;
181 if (c2 == EOS)
182 return (NULL);
183 if (c <= test && test <= c2)
184 ok = 1;
185 } else if (c == test)
186 ok = 1;
187 }
188 return (ok == negate ? NULL : pattern);
189 }