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