1*d4a07e70Sfengbojiang /*-
2*d4a07e70Sfengbojiang * SPDX-License-Identifier: BSD-3-Clause
3*d4a07e70Sfengbojiang *
4*d4a07e70Sfengbojiang * Copyright (c) 1989, 1993, 1994
5*d4a07e70Sfengbojiang * The Regents of the University of California. All rights reserved.
6*d4a07e70Sfengbojiang *
7*d4a07e70Sfengbojiang * This code is derived from software contributed to Berkeley by
8*d4a07e70Sfengbojiang * Guido van Rossum.
9*d4a07e70Sfengbojiang *
10*d4a07e70Sfengbojiang * Redistribution and use in source and binary forms, with or without
11*d4a07e70Sfengbojiang * modification, are permitted provided that the following conditions
12*d4a07e70Sfengbojiang * are met:
13*d4a07e70Sfengbojiang * 1. Redistributions of source code must retain the above copyright
14*d4a07e70Sfengbojiang * notice, this list of conditions and the following disclaimer.
15*d4a07e70Sfengbojiang * 2. Redistributions in binary form must reproduce the above copyright
16*d4a07e70Sfengbojiang * notice, this list of conditions and the following disclaimer in the
17*d4a07e70Sfengbojiang * documentation and/or other materials provided with the distribution.
18*d4a07e70Sfengbojiang * 3. Neither the name of the University nor the names of its contributors
19*d4a07e70Sfengbojiang * may be used to endorse or promote products derived from this software
20*d4a07e70Sfengbojiang * without specific prior written permission.
21*d4a07e70Sfengbojiang *
22*d4a07e70Sfengbojiang * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23*d4a07e70Sfengbojiang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24*d4a07e70Sfengbojiang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25*d4a07e70Sfengbojiang * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26*d4a07e70Sfengbojiang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27*d4a07e70Sfengbojiang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28*d4a07e70Sfengbojiang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29*d4a07e70Sfengbojiang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30*d4a07e70Sfengbojiang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31*d4a07e70Sfengbojiang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*d4a07e70Sfengbojiang * SUCH DAMAGE.
33*d4a07e70Sfengbojiang */
34*d4a07e70Sfengbojiang
35*d4a07e70Sfengbojiang #include <sys/cdefs.h>
36*d4a07e70Sfengbojiang #include <sys/cdefs.h>
37*d4a07e70Sfengbojiang #ifndef FSTACK
38*d4a07e70Sfengbojiang __FBSDID("$FreeBSD$");
39*d4a07e70Sfengbojiang #endif
40*d4a07e70Sfengbojiang
41*d4a07e70Sfengbojiang /*
42*d4a07e70Sfengbojiang * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
43*d4a07e70Sfengbojiang * Compares a filename or pathname to a pattern.
44*d4a07e70Sfengbojiang */
45*d4a07e70Sfengbojiang
46*d4a07e70Sfengbojiang #include <sys/param.h>
47*d4a07e70Sfengbojiang #ifndef FSTACK
48*d4a07e70Sfengbojiang #include <sys/ctype.h>
49*d4a07e70Sfengbojiang #include <sys/libkern.h>
50*d4a07e70Sfengbojiang #else
51*d4a07e70Sfengbojiang #include <string.h>
52*d4a07e70Sfengbojiang #include <ctype.h>
53*d4a07e70Sfengbojiang #include <stdint.h>
54*d4a07e70Sfengbojiang
55*d4a07e70Sfengbojiang /* fnmatch() return values. */
56*d4a07e70Sfengbojiang #define FNM_NOMATCH 1 /* Match failed. */
57*d4a07e70Sfengbojiang
58*d4a07e70Sfengbojiang /* fnmatch() flags. */
59*d4a07e70Sfengbojiang #define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
60*d4a07e70Sfengbojiang #define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
61*d4a07e70Sfengbojiang #define FNM_PERIOD 0x04 /* Period must be matched by period. */
62*d4a07e70Sfengbojiang #define FNM_LEADING_DIR 0x08 /* Ignore /<tail> after Imatch. */
63*d4a07e70Sfengbojiang #define FNM_CASEFOLD 0x10 /* Case insensitive search. */
64*d4a07e70Sfengbojiang #define FNM_IGNORECASE FNM_CASEFOLD
65*d4a07e70Sfengbojiang #define FNM_FILE_NAME FNM_PATHNAME
66*d4a07e70Sfengbojiang
67*d4a07e70Sfengbojiang #endif
68*d4a07e70Sfengbojiang
69*d4a07e70Sfengbojiang #define EOS '\0'
70*d4a07e70Sfengbojiang
71*d4a07e70Sfengbojiang #define RANGE_MATCH 1
72*d4a07e70Sfengbojiang #define RANGE_NOMATCH 0
73*d4a07e70Sfengbojiang #define RANGE_ERROR (-1)
74*d4a07e70Sfengbojiang
75*d4a07e70Sfengbojiang
76*d4a07e70Sfengbojiang static int rangematch(const char *, char, int, char **);
77*d4a07e70Sfengbojiang
78*d4a07e70Sfengbojiang int
fnmatch(const char * pattern,const char * string,int flags)79*d4a07e70Sfengbojiang fnmatch(const char *pattern, const char *string, int flags)
80*d4a07e70Sfengbojiang {
81*d4a07e70Sfengbojiang const char *stringstart;
82*d4a07e70Sfengbojiang char *newp;
83*d4a07e70Sfengbojiang char c, test;
84*d4a07e70Sfengbojiang
85*d4a07e70Sfengbojiang for (stringstart = string;;)
86*d4a07e70Sfengbojiang switch (c = *pattern++) {
87*d4a07e70Sfengbojiang case EOS:
88*d4a07e70Sfengbojiang if ((flags & FNM_LEADING_DIR) && *string == '/')
89*d4a07e70Sfengbojiang return (0);
90*d4a07e70Sfengbojiang return (*string == EOS ? 0 : FNM_NOMATCH);
91*d4a07e70Sfengbojiang case '?':
92*d4a07e70Sfengbojiang if (*string == EOS)
93*d4a07e70Sfengbojiang return (FNM_NOMATCH);
94*d4a07e70Sfengbojiang if (*string == '/' && (flags & FNM_PATHNAME))
95*d4a07e70Sfengbojiang return (FNM_NOMATCH);
96*d4a07e70Sfengbojiang if (*string == '.' && (flags & FNM_PERIOD) &&
97*d4a07e70Sfengbojiang (string == stringstart ||
98*d4a07e70Sfengbojiang ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
99*d4a07e70Sfengbojiang return (FNM_NOMATCH);
100*d4a07e70Sfengbojiang ++string;
101*d4a07e70Sfengbojiang break;
102*d4a07e70Sfengbojiang case '*':
103*d4a07e70Sfengbojiang c = *pattern;
104*d4a07e70Sfengbojiang /* Collapse multiple stars. */
105*d4a07e70Sfengbojiang while (c == '*')
106*d4a07e70Sfengbojiang c = *++pattern;
107*d4a07e70Sfengbojiang
108*d4a07e70Sfengbojiang if (*string == '.' && (flags & FNM_PERIOD) &&
109*d4a07e70Sfengbojiang (string == stringstart ||
110*d4a07e70Sfengbojiang ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
111*d4a07e70Sfengbojiang return (FNM_NOMATCH);
112*d4a07e70Sfengbojiang
113*d4a07e70Sfengbojiang /* Optimize for pattern with * at end or before /. */
114*d4a07e70Sfengbojiang if (c == EOS)
115*d4a07e70Sfengbojiang if (flags & FNM_PATHNAME)
116*d4a07e70Sfengbojiang return ((flags & FNM_LEADING_DIR) ||
117*d4a07e70Sfengbojiang strchr(string, '/') == NULL ?
118*d4a07e70Sfengbojiang 0 : FNM_NOMATCH);
119*d4a07e70Sfengbojiang else
120*d4a07e70Sfengbojiang return (0);
121*d4a07e70Sfengbojiang else if (c == '/' && flags & FNM_PATHNAME) {
122*d4a07e70Sfengbojiang if ((string = strchr(string, '/')) == NULL)
123*d4a07e70Sfengbojiang return (FNM_NOMATCH);
124*d4a07e70Sfengbojiang break;
125*d4a07e70Sfengbojiang }
126*d4a07e70Sfengbojiang
127*d4a07e70Sfengbojiang /* General case, use recursion. */
128*d4a07e70Sfengbojiang while ((test = *string) != EOS) {
129*d4a07e70Sfengbojiang if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
130*d4a07e70Sfengbojiang return (0);
131*d4a07e70Sfengbojiang if (test == '/' && flags & FNM_PATHNAME)
132*d4a07e70Sfengbojiang break;
133*d4a07e70Sfengbojiang ++string;
134*d4a07e70Sfengbojiang }
135*d4a07e70Sfengbojiang return (FNM_NOMATCH);
136*d4a07e70Sfengbojiang case '[':
137*d4a07e70Sfengbojiang if (*string == EOS)
138*d4a07e70Sfengbojiang return (FNM_NOMATCH);
139*d4a07e70Sfengbojiang if (*string == '/' && (flags & FNM_PATHNAME))
140*d4a07e70Sfengbojiang return (FNM_NOMATCH);
141*d4a07e70Sfengbojiang if (*string == '.' && (flags & FNM_PERIOD) &&
142*d4a07e70Sfengbojiang (string == stringstart ||
143*d4a07e70Sfengbojiang ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
144*d4a07e70Sfengbojiang return (FNM_NOMATCH);
145*d4a07e70Sfengbojiang
146*d4a07e70Sfengbojiang switch (rangematch(pattern, *string, flags, &newp)) {
147*d4a07e70Sfengbojiang case RANGE_ERROR:
148*d4a07e70Sfengbojiang goto norm;
149*d4a07e70Sfengbojiang case RANGE_MATCH:
150*d4a07e70Sfengbojiang pattern = newp;
151*d4a07e70Sfengbojiang break;
152*d4a07e70Sfengbojiang case RANGE_NOMATCH:
153*d4a07e70Sfengbojiang return (FNM_NOMATCH);
154*d4a07e70Sfengbojiang }
155*d4a07e70Sfengbojiang ++string;
156*d4a07e70Sfengbojiang break;
157*d4a07e70Sfengbojiang case '\\':
158*d4a07e70Sfengbojiang if (!(flags & FNM_NOESCAPE)) {
159*d4a07e70Sfengbojiang if ((c = *pattern++) == EOS) {
160*d4a07e70Sfengbojiang c = '\\';
161*d4a07e70Sfengbojiang --pattern;
162*d4a07e70Sfengbojiang }
163*d4a07e70Sfengbojiang }
164*d4a07e70Sfengbojiang /* FALLTHROUGH */
165*d4a07e70Sfengbojiang default:
166*d4a07e70Sfengbojiang norm:
167*d4a07e70Sfengbojiang if (c == *string)
168*d4a07e70Sfengbojiang ;
169*d4a07e70Sfengbojiang else if ((flags & FNM_CASEFOLD) &&
170*d4a07e70Sfengbojiang (tolower((unsigned char)c) ==
171*d4a07e70Sfengbojiang tolower((unsigned char)*string)))
172*d4a07e70Sfengbojiang ;
173*d4a07e70Sfengbojiang else
174*d4a07e70Sfengbojiang return (FNM_NOMATCH);
175*d4a07e70Sfengbojiang string++;
176*d4a07e70Sfengbojiang break;
177*d4a07e70Sfengbojiang }
178*d4a07e70Sfengbojiang /* NOTREACHED */
179*d4a07e70Sfengbojiang }
180*d4a07e70Sfengbojiang
181*d4a07e70Sfengbojiang static int
rangematch(const char * pattern,char test,int flags,char ** newp)182*d4a07e70Sfengbojiang rangematch(const char *pattern, char test, int flags, char **newp)
183*d4a07e70Sfengbojiang {
184*d4a07e70Sfengbojiang int negate, ok;
185*d4a07e70Sfengbojiang char c, c2;
186*d4a07e70Sfengbojiang
187*d4a07e70Sfengbojiang /*
188*d4a07e70Sfengbojiang * A bracket expression starting with an unquoted circumflex
189*d4a07e70Sfengbojiang * character produces unspecified results (IEEE 1003.2-1992,
190*d4a07e70Sfengbojiang * 3.13.2). This implementation treats it like '!', for
191*d4a07e70Sfengbojiang * consistency with the regular expression syntax.
192*d4a07e70Sfengbojiang * J.T. Conklin ([email protected])
193*d4a07e70Sfengbojiang */
194*d4a07e70Sfengbojiang if ( (negate = (*pattern == '!' || *pattern == '^')) )
195*d4a07e70Sfengbojiang ++pattern;
196*d4a07e70Sfengbojiang
197*d4a07e70Sfengbojiang if (flags & FNM_CASEFOLD)
198*d4a07e70Sfengbojiang test = tolower((unsigned char)test);
199*d4a07e70Sfengbojiang
200*d4a07e70Sfengbojiang /*
201*d4a07e70Sfengbojiang * A right bracket shall lose its special meaning and represent
202*d4a07e70Sfengbojiang * itself in a bracket expression if it occurs first in the list.
203*d4a07e70Sfengbojiang * -- POSIX.2 2.8.3.2
204*d4a07e70Sfengbojiang */
205*d4a07e70Sfengbojiang ok = 0;
206*d4a07e70Sfengbojiang c = *pattern++;
207*d4a07e70Sfengbojiang do {
208*d4a07e70Sfengbojiang if (c == '\\' && !(flags & FNM_NOESCAPE))
209*d4a07e70Sfengbojiang c = *pattern++;
210*d4a07e70Sfengbojiang if (c == EOS)
211*d4a07e70Sfengbojiang return (RANGE_ERROR);
212*d4a07e70Sfengbojiang
213*d4a07e70Sfengbojiang if (c == '/' && (flags & FNM_PATHNAME))
214*d4a07e70Sfengbojiang return (RANGE_NOMATCH);
215*d4a07e70Sfengbojiang
216*d4a07e70Sfengbojiang if (flags & FNM_CASEFOLD)
217*d4a07e70Sfengbojiang c = tolower((unsigned char)c);
218*d4a07e70Sfengbojiang
219*d4a07e70Sfengbojiang if (*pattern == '-'
220*d4a07e70Sfengbojiang && (c2 = *(pattern+1)) != EOS && c2 != ']') {
221*d4a07e70Sfengbojiang pattern += 2;
222*d4a07e70Sfengbojiang if (c2 == '\\' && !(flags & FNM_NOESCAPE))
223*d4a07e70Sfengbojiang c2 = *pattern++;
224*d4a07e70Sfengbojiang if (c2 == EOS)
225*d4a07e70Sfengbojiang return (RANGE_ERROR);
226*d4a07e70Sfengbojiang
227*d4a07e70Sfengbojiang if (flags & FNM_CASEFOLD)
228*d4a07e70Sfengbojiang c2 = tolower((unsigned char)c2);
229*d4a07e70Sfengbojiang
230*d4a07e70Sfengbojiang if (c <= test && test <= c2)
231*d4a07e70Sfengbojiang ok = 1;
232*d4a07e70Sfengbojiang } else if (c == test)
233*d4a07e70Sfengbojiang ok = 1;
234*d4a07e70Sfengbojiang } while ((c = *pattern++) != ']');
235*d4a07e70Sfengbojiang
236*d4a07e70Sfengbojiang *newp = (char *)(uintptr_t)pattern;
237*d4a07e70Sfengbojiang return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
238*d4a07e70Sfengbojiang }
239