1*a8fa202aSchristos /* $NetBSD: fnmatch.c,v 1.1.1.1 2016/01/10 21:36:18 christos Exp $ */
2*a8fa202aSchristos
3*a8fa202aSchristos /* Copyright 1991, 1992, 1993, 1996, 1997, 2000 Free Software Foundation, Inc.
4*a8fa202aSchristos
5*a8fa202aSchristos This program is free software; you can redistribute it and/or modify
6*a8fa202aSchristos it under the terms of the GNU General Public License as published by
7*a8fa202aSchristos the Free Software Foundation; either version 2, or (at your option)
8*a8fa202aSchristos any later version.
9*a8fa202aSchristos
10*a8fa202aSchristos This program is distributed in the hope that it will be useful,
11*a8fa202aSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
12*a8fa202aSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*a8fa202aSchristos GNU General Public License for more details.
14*a8fa202aSchristos
15*a8fa202aSchristos You should have received a copy of the GNU General Public License
16*a8fa202aSchristos along with this program; if not, write to the Free Software Foundation,
17*a8fa202aSchristos Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18*a8fa202aSchristos
19*a8fa202aSchristos #if HAVE_CONFIG_H
20*a8fa202aSchristos # include <config.h>
21*a8fa202aSchristos #endif
22*a8fa202aSchristos
23*a8fa202aSchristos /* Enable GNU extensions in fnmatch.h. */
24*a8fa202aSchristos #ifndef _GNU_SOURCE
25*a8fa202aSchristos # define _GNU_SOURCE 1
26*a8fa202aSchristos #endif
27*a8fa202aSchristos
28*a8fa202aSchristos #include <errno.h>
29*a8fa202aSchristos #include <fnmatch.h>
30*a8fa202aSchristos #include <ctype.h>
31*a8fa202aSchristos
32*a8fa202aSchristos #if defined STDC_HEADERS || !defined isascii
33*a8fa202aSchristos # define IN_CTYPE_DOMAIN(c) 1
34*a8fa202aSchristos #else
35*a8fa202aSchristos # define IN_CTYPE_DOMAIN(c) isascii (c)
36*a8fa202aSchristos #endif
37*a8fa202aSchristos
38*a8fa202aSchristos #define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
39*a8fa202aSchristos
40*a8fa202aSchristos
41*a8fa202aSchristos #ifndef errno
42*a8fa202aSchristos extern int errno;
43*a8fa202aSchristos #endif
44*a8fa202aSchristos
45*a8fa202aSchristos /* Match STRING against the filename pattern PATTERN, returning zero if
46*a8fa202aSchristos it matches, nonzero if not. */
47*a8fa202aSchristos int
fnmatch(const char * pattern,const char * string,int flags)48*a8fa202aSchristos fnmatch (const char *pattern, const char *string, int flags)
49*a8fa202aSchristos {
50*a8fa202aSchristos register const char *p = pattern, *n = string;
51*a8fa202aSchristos register char c;
52*a8fa202aSchristos
53*a8fa202aSchristos /* Note that this evaluates C many times. */
54*a8fa202aSchristos #define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER ((unsigned char) (c)) \
55*a8fa202aSchristos ? tolower ((unsigned char) (c)) \
56*a8fa202aSchristos : (c))
57*a8fa202aSchristos
58*a8fa202aSchristos while ((c = *p++) != '\0')
59*a8fa202aSchristos {
60*a8fa202aSchristos c = FOLD (c);
61*a8fa202aSchristos
62*a8fa202aSchristos switch (c)
63*a8fa202aSchristos {
64*a8fa202aSchristos case '?':
65*a8fa202aSchristos if (*n == '\0')
66*a8fa202aSchristos return FNM_NOMATCH;
67*a8fa202aSchristos else if ((flags & FNM_FILE_NAME) && *n == '/')
68*a8fa202aSchristos return FNM_NOMATCH;
69*a8fa202aSchristos else if ((flags & FNM_PERIOD) && *n == '.' &&
70*a8fa202aSchristos (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
71*a8fa202aSchristos return FNM_NOMATCH;
72*a8fa202aSchristos break;
73*a8fa202aSchristos
74*a8fa202aSchristos case '\\':
75*a8fa202aSchristos if (!(flags & FNM_NOESCAPE))
76*a8fa202aSchristos {
77*a8fa202aSchristos c = *p++;
78*a8fa202aSchristos if (c == '\0')
79*a8fa202aSchristos /* Trailing \ loses. */
80*a8fa202aSchristos return FNM_NOMATCH;
81*a8fa202aSchristos c = FOLD (c);
82*a8fa202aSchristos }
83*a8fa202aSchristos if (FOLD (*n) != c)
84*a8fa202aSchristos return FNM_NOMATCH;
85*a8fa202aSchristos break;
86*a8fa202aSchristos
87*a8fa202aSchristos case '*':
88*a8fa202aSchristos if ((flags & FNM_PERIOD) && *n == '.' &&
89*a8fa202aSchristos (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
90*a8fa202aSchristos return FNM_NOMATCH;
91*a8fa202aSchristos
92*a8fa202aSchristos for (c = *p++; c == '?' || c == '*'; c = *p++)
93*a8fa202aSchristos {
94*a8fa202aSchristos if (c == '?')
95*a8fa202aSchristos {
96*a8fa202aSchristos /* A ? needs to match one character. */
97*a8fa202aSchristos if (*n == '\0' || (*n == '/' && (flags & FNM_FILE_NAME)))
98*a8fa202aSchristos /* There isn't another character; no match. */
99*a8fa202aSchristos return FNM_NOMATCH;
100*a8fa202aSchristos else
101*a8fa202aSchristos /* One character of the string is consumed in matching
102*a8fa202aSchristos this ? wildcard, so *??? won't match if there are
103*a8fa202aSchristos less than three characters. */
104*a8fa202aSchristos ++n;
105*a8fa202aSchristos }
106*a8fa202aSchristos }
107*a8fa202aSchristos
108*a8fa202aSchristos if (c == '\0')
109*a8fa202aSchristos {
110*a8fa202aSchristos if ((flags & (FNM_FILE_NAME | FNM_LEADING_DIR)) == FNM_FILE_NAME)
111*a8fa202aSchristos for (; *n != '\0'; n++)
112*a8fa202aSchristos if (*n == '/')
113*a8fa202aSchristos return FNM_NOMATCH;
114*a8fa202aSchristos return 0;
115*a8fa202aSchristos }
116*a8fa202aSchristos
117*a8fa202aSchristos {
118*a8fa202aSchristos char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
119*a8fa202aSchristos c1 = FOLD (c1);
120*a8fa202aSchristos for (--p; *n != '\0'; ++n)
121*a8fa202aSchristos if ((c == '[' || FOLD (*n) == c1) &&
122*a8fa202aSchristos fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
123*a8fa202aSchristos return 0;
124*a8fa202aSchristos else if (*n == '/' && (flags & FNM_FILE_NAME))
125*a8fa202aSchristos break;
126*a8fa202aSchristos return FNM_NOMATCH;
127*a8fa202aSchristos }
128*a8fa202aSchristos
129*a8fa202aSchristos case '[':
130*a8fa202aSchristos {
131*a8fa202aSchristos /* Nonzero if the sense of the character class is inverted. */
132*a8fa202aSchristos register int not;
133*a8fa202aSchristos
134*a8fa202aSchristos if (*n == '\0')
135*a8fa202aSchristos return FNM_NOMATCH;
136*a8fa202aSchristos
137*a8fa202aSchristos if ((flags & FNM_PERIOD) && *n == '.' &&
138*a8fa202aSchristos (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
139*a8fa202aSchristos return FNM_NOMATCH;
140*a8fa202aSchristos
141*a8fa202aSchristos not = (*p == '!' || *p == '^');
142*a8fa202aSchristos if (not)
143*a8fa202aSchristos ++p;
144*a8fa202aSchristos
145*a8fa202aSchristos c = *p++;
146*a8fa202aSchristos for (;;)
147*a8fa202aSchristos {
148*a8fa202aSchristos register char cstart = c, cend = c;
149*a8fa202aSchristos
150*a8fa202aSchristos if (!(flags & FNM_NOESCAPE) && c == '\\')
151*a8fa202aSchristos {
152*a8fa202aSchristos if (*p == '\0')
153*a8fa202aSchristos return FNM_NOMATCH;
154*a8fa202aSchristos cstart = cend = *p++;
155*a8fa202aSchristos }
156*a8fa202aSchristos
157*a8fa202aSchristos cstart = cend = FOLD (cstart);
158*a8fa202aSchristos
159*a8fa202aSchristos if (c == '\0')
160*a8fa202aSchristos /* [ (unterminated) loses. */
161*a8fa202aSchristos return FNM_NOMATCH;
162*a8fa202aSchristos
163*a8fa202aSchristos c = *p++;
164*a8fa202aSchristos c = FOLD (c);
165*a8fa202aSchristos
166*a8fa202aSchristos if ((flags & FNM_FILE_NAME) && c == '/')
167*a8fa202aSchristos /* [/] can never match. */
168*a8fa202aSchristos return FNM_NOMATCH;
169*a8fa202aSchristos
170*a8fa202aSchristos if (c == '-' && *p != ']')
171*a8fa202aSchristos {
172*a8fa202aSchristos cend = *p++;
173*a8fa202aSchristos if (!(flags & FNM_NOESCAPE) && cend == '\\')
174*a8fa202aSchristos cend = *p++;
175*a8fa202aSchristos if (cend == '\0')
176*a8fa202aSchristos return FNM_NOMATCH;
177*a8fa202aSchristos cend = FOLD (cend);
178*a8fa202aSchristos
179*a8fa202aSchristos c = *p++;
180*a8fa202aSchristos }
181*a8fa202aSchristos
182*a8fa202aSchristos if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
183*a8fa202aSchristos goto matched;
184*a8fa202aSchristos
185*a8fa202aSchristos if (c == ']')
186*a8fa202aSchristos break;
187*a8fa202aSchristos }
188*a8fa202aSchristos if (!not)
189*a8fa202aSchristos return FNM_NOMATCH;
190*a8fa202aSchristos break;
191*a8fa202aSchristos
192*a8fa202aSchristos matched:;
193*a8fa202aSchristos /* Skip the rest of the [...] that already matched. */
194*a8fa202aSchristos while (c != ']')
195*a8fa202aSchristos {
196*a8fa202aSchristos if (c == '\0')
197*a8fa202aSchristos /* [... (unterminated) loses. */
198*a8fa202aSchristos return FNM_NOMATCH;
199*a8fa202aSchristos
200*a8fa202aSchristos c = *p++;
201*a8fa202aSchristos if (!(flags & FNM_NOESCAPE) && c == '\\')
202*a8fa202aSchristos {
203*a8fa202aSchristos if (*p == '\0')
204*a8fa202aSchristos return FNM_NOMATCH;
205*a8fa202aSchristos /* XXX 1003.2d11 is unclear if this is right. */
206*a8fa202aSchristos ++p;
207*a8fa202aSchristos }
208*a8fa202aSchristos }
209*a8fa202aSchristos if (not)
210*a8fa202aSchristos return FNM_NOMATCH;
211*a8fa202aSchristos }
212*a8fa202aSchristos break;
213*a8fa202aSchristos
214*a8fa202aSchristos default:
215*a8fa202aSchristos if (c != FOLD (*n))
216*a8fa202aSchristos return FNM_NOMATCH;
217*a8fa202aSchristos }
218*a8fa202aSchristos
219*a8fa202aSchristos ++n;
220*a8fa202aSchristos }
221*a8fa202aSchristos
222*a8fa202aSchristos if (*n == '\0')
223*a8fa202aSchristos return 0;
224*a8fa202aSchristos
225*a8fa202aSchristos if ((flags & FNM_LEADING_DIR) && *n == '/')
226*a8fa202aSchristos /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
227*a8fa202aSchristos return 0;
228*a8fa202aSchristos
229*a8fa202aSchristos return FNM_NOMATCH;
230*a8fa202aSchristos
231*a8fa202aSchristos #undef FOLD
232*a8fa202aSchristos }
233