fnmatch.c revision 1.24.4.1 1 1.24.4.1 yamt /* $NetBSD: fnmatch.c,v 1.24.4.1 2012/04/17 00:05:18 yamt Exp $ */
2 1.11 cgd
3 1.1 cgd /*
4 1.11 cgd * Copyright (c) 1989, 1993, 1994
5 1.6 cgd * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * This code is derived from software contributed to Berkeley by
8 1.1 cgd * Guido van Rossum.
9 1.1 cgd *
10 1.1 cgd * Redistribution and use in source and binary forms, with or without
11 1.1 cgd * modification, are permitted provided that the following conditions
12 1.1 cgd * are met:
13 1.1 cgd * 1. Redistributions of source code must retain the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer.
15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 cgd * notice, this list of conditions and the following disclaimer in the
17 1.1 cgd * documentation and/or other materials provided with the distribution.
18 1.20 agc * 3. Neither the name of the University nor the names of its contributors
19 1.1 cgd * may be used to endorse or promote products derived from this software
20 1.1 cgd * without specific prior written permission.
21 1.1 cgd *
22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 1.1 cgd * SUCH DAMAGE.
33 1.1 cgd */
34 1.1 cgd
35 1.12 christos #include <sys/cdefs.h>
36 1.1 cgd #if defined(LIBC_SCCS) && !defined(lint)
37 1.11 cgd #if 0
38 1.11 cgd static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94";
39 1.11 cgd #else
40 1.24.4.1 yamt __RCSID("$NetBSD: fnmatch.c,v 1.24.4.1 2012/04/17 00:05:18 yamt Exp $");
41 1.11 cgd #endif
42 1.1 cgd #endif /* LIBC_SCCS and not lint */
43 1.1 cgd
44 1.1 cgd /*
45 1.7 jtc * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
46 1.1 cgd * Compares a filename or pathname to a pattern.
47 1.1 cgd */
48 1.1 cgd
49 1.13 jtc #include "namespace.h"
50 1.15 lukem
51 1.15 lukem #include <assert.h>
52 1.18 thorpej #include <ctype.h>
53 1.3 jtc #include <fnmatch.h>
54 1.1 cgd #include <string.h>
55 1.13 jtc
56 1.13 jtc #ifdef __weak_alias
57 1.17 mycroft __weak_alias(fnmatch,_fnmatch)
58 1.13 jtc #endif
59 1.1 cgd
60 1.1 cgd #define EOS '\0'
61 1.1 cgd
62 1.21 perry static inline int
63 1.18 thorpej foldcase(int ch, int flags)
64 1.18 thorpej {
65 1.18 thorpej
66 1.18 thorpej if ((flags & FNM_CASEFOLD) != 0 && isupper(ch))
67 1.22 christos return tolower(ch);
68 1.22 christos return ch;
69 1.18 thorpej }
70 1.18 thorpej
71 1.18 thorpej #define FOLDCASE(ch, flags) foldcase((unsigned char)(ch), (flags))
72 1.18 thorpej
73 1.22 christos static const char *
74 1.22 christos rangematch(const char *pattern, int test, int flags)
75 1.22 christos {
76 1.22 christos int negate, ok;
77 1.22 christos char c, c2;
78 1.22 christos
79 1.22 christos _DIAGASSERT(pattern != NULL);
80 1.22 christos
81 1.22 christos /*
82 1.22 christos * A bracket expression starting with an unquoted circumflex
83 1.22 christos * character produces unspecified results (IEEE 1003.2-1992,
84 1.22 christos * 3.13.2). This implementation treats it like '!', for
85 1.22 christos * consistency with the regular expression syntax.
86 1.22 christos * J.T. Conklin (conklin (at) ngai.kaleida.com)
87 1.22 christos */
88 1.22 christos if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
89 1.22 christos ++pattern;
90 1.22 christos
91 1.22 christos for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) {
92 1.22 christos if (c == '\\' && !(flags & FNM_NOESCAPE))
93 1.22 christos c = FOLDCASE(*pattern++, flags);
94 1.22 christos if (c == EOS)
95 1.22 christos return NULL;
96 1.22 christos if (*pattern == '-'
97 1.22 christos && (c2 = FOLDCASE(*(pattern + 1), flags)) != EOS &&
98 1.22 christos c2 != ']') {
99 1.22 christos pattern += 2;
100 1.22 christos if (c2 == '\\' && !(flags & FNM_NOESCAPE))
101 1.22 christos c2 = FOLDCASE(*pattern++, flags);
102 1.22 christos if (c2 == EOS)
103 1.22 christos return NULL;
104 1.22 christos if (c <= test && test <= c2)
105 1.22 christos ok = 1;
106 1.22 christos } else if (c == test)
107 1.22 christos ok = 1;
108 1.22 christos }
109 1.22 christos return ok == negate ? NULL : pattern;
110 1.22 christos }
111 1.22 christos
112 1.22 christos
113 1.22 christos static int
114 1.22 christos fnmatchx(const char *pattern, const char *string, int flags, size_t recursion)
115 1.1 cgd {
116 1.11 cgd const char *stringstart;
117 1.11 cgd char c, test;
118 1.1 cgd
119 1.15 lukem _DIAGASSERT(pattern != NULL);
120 1.15 lukem _DIAGASSERT(string != NULL);
121 1.15 lukem
122 1.22 christos if (recursion-- == 0)
123 1.22 christos return FNM_NORES;
124 1.22 christos
125 1.24 christos for (stringstart = string;;) {
126 1.18 thorpej switch (c = FOLDCASE(*pattern++, flags)) {
127 1.1 cgd case EOS:
128 1.19 provos if ((flags & FNM_LEADING_DIR) && *string == '/')
129 1.22 christos return 0;
130 1.22 christos return *string == EOS ? 0 : FNM_NOMATCH;
131 1.1 cgd case '?':
132 1.8 jtc if (*string == EOS)
133 1.22 christos return FNM_NOMATCH;
134 1.8 jtc if (*string == '/' && (flags & FNM_PATHNAME))
135 1.22 christos return FNM_NOMATCH;
136 1.8 jtc if (*string == '.' && (flags & FNM_PERIOD) &&
137 1.11 cgd (string == stringstart ||
138 1.11 cgd ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
139 1.22 christos return FNM_NOMATCH;
140 1.8 jtc ++string;
141 1.1 cgd break;
142 1.1 cgd case '*':
143 1.18 thorpej c = FOLDCASE(*pattern, flags);
144 1.3 jtc /* Collapse multiple stars. */
145 1.1 cgd while (c == '*')
146 1.18 thorpej c = FOLDCASE(*++pattern, flags);
147 1.1 cgd
148 1.8 jtc if (*string == '.' && (flags & FNM_PERIOD) &&
149 1.11 cgd (string == stringstart ||
150 1.11 cgd ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
151 1.22 christos return FNM_NOMATCH;
152 1.8 jtc
153 1.3 jtc /* Optimize for pattern with * at end or before /. */
154 1.14 christos if (c == EOS) {
155 1.1 cgd if (flags & FNM_PATHNAME)
156 1.22 christos return (flags & FNM_LEADING_DIR) ||
157 1.19 provos strchr(string, '/') == NULL ?
158 1.22 christos 0 : FNM_NOMATCH;
159 1.1 cgd else
160 1.22 christos return 0;
161 1.14 christos } else if (c == '/' && flags & FNM_PATHNAME) {
162 1.10 jtc if ((string = strchr(string, '/')) == NULL)
163 1.22 christos return FNM_NOMATCH;
164 1.1 cgd break;
165 1.1 cgd }
166 1.1 cgd
167 1.3 jtc /* General case, use recursion. */
168 1.18 thorpej while ((test = FOLDCASE(*string, flags)) != EOS) {
169 1.22 christos int e;
170 1.22 christos switch ((e = fnmatchx(pattern, string,
171 1.22 christos flags & ~FNM_PERIOD, recursion))) {
172 1.22 christos case FNM_NOMATCH:
173 1.22 christos break;
174 1.22 christos default:
175 1.22 christos return e;
176 1.22 christos }
177 1.1 cgd if (test == '/' && flags & FNM_PATHNAME)
178 1.1 cgd break;
179 1.1 cgd ++string;
180 1.1 cgd }
181 1.22 christos return FNM_NOMATCH;
182 1.1 cgd case '[':
183 1.8 jtc if (*string == EOS)
184 1.22 christos return FNM_NOMATCH;
185 1.8 jtc if (*string == '/' && flags & FNM_PATHNAME)
186 1.22 christos return FNM_NOMATCH;
187 1.22 christos if ((pattern = rangematch(pattern,
188 1.22 christos FOLDCASE(*string, flags), flags)) == NULL)
189 1.22 christos return FNM_NOMATCH;
190 1.8 jtc ++string;
191 1.1 cgd break;
192 1.1 cgd case '\\':
193 1.3 jtc if (!(flags & FNM_NOESCAPE)) {
194 1.18 thorpej if ((c = FOLDCASE(*pattern++, flags)) == EOS) {
195 1.24.4.1 yamt c = '\0';
196 1.1 cgd --pattern;
197 1.1 cgd }
198 1.1 cgd }
199 1.1 cgd /* FALLTHROUGH */
200 1.1 cgd default:
201 1.18 thorpej if (c != FOLDCASE(*string++, flags))
202 1.22 christos return FNM_NOMATCH;
203 1.1 cgd break;
204 1.1 cgd }
205 1.24 christos }
206 1.3 jtc /* NOTREACHED */
207 1.3 jtc }
208 1.3 jtc
209 1.22 christos int
210 1.22 christos fnmatch(const char *pattern, const char *string, int flags)
211 1.3 jtc {
212 1.23 christos return fnmatchx(pattern, string, flags, 64);
213 1.1 cgd }
214