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