]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/fnmatch.c
added (unsigned char) to prevent assertion in win32
[bacula/bacula] / bacula / src / lib / 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 #include "bacula.h"
18 #include "fnmatch.h"
19
20
21 /* Comment out all this code if we are using the GNU C Library, and are not
22    actually compiling the library itself.  This code is part of the GNU C
23    Library, but also included in many other GNU distributions.  Compiling
24    and linking in this code is a waste when using the GNU C library
25    (especially if it is a shared library).  Rather than having every GNU
26    program understand `configure --with-gnu-libc' and omit the object files,
27    it is simpler to just do this in the source for each such file.  */
28
29 #if defined _LIBC || !defined __GNU_LIBRARY__
30
31
32 # if defined STDC_HEADERS || !defined isascii
33 #  define ISASCII(c) 1
34 # else
35 #  define ISASCII(c) isascii(c)
36 # endif
37
38 #ifndef ISUPPER
39 # define ISUPPER(c) (ISASCII (c) && isupper (c))
40 #endif
41
42
43 # ifndef errno
44 extern int errno;
45 # endif
46
47 /* Match STRING against the filename pattern PATTERN, returning zero if
48    it matches, nonzero if not.  */
49 int
50 fnmatch (const char *pattern, const char *string, int flags)
51 {
52   register const char *p = pattern, *n = string;
53   register char c;
54
55 /* Note that this evaluates C many times.  */
56 # define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
57
58   while ((c = *p++) != '\0')
59     {
60       c = FOLD (c);
61
62       switch (c)
63         {
64         case '?':
65           if (*n == '\0')
66             return FNM_NOMATCH;
67           else if ((flags & FNM_FILE_NAME) && *n == '/')
68             return FNM_NOMATCH;
69           else if ((flags & FNM_PERIOD) && *n == '.' &&
70                    (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
71             return FNM_NOMATCH;
72           break;
73
74         case '\\':
75           if (!(flags & FNM_NOESCAPE))
76             {
77               c = *p++;
78               if (c == '\0')
79                 /* Trailing \ loses.  */
80                 return FNM_NOMATCH;
81               c = FOLD (c);
82             }
83           if (FOLD (*n) != c)
84             return FNM_NOMATCH;
85           break;
86
87         case '*':
88           if ((flags & FNM_PERIOD) && *n == '.' &&
89               (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
90             return FNM_NOMATCH;
91
92           for (c = *p++; c == '?' || c == '*'; c = *p++)
93             {
94               if ((flags & FNM_FILE_NAME) && *n == '/')
95                 /* A slash does not match a wildcard under FNM_FILE_NAME.  */
96                 return FNM_NOMATCH;
97               else if (c == '?')
98                 {
99                   /* A ? needs to match one character.  */
100                   if (*n == '\0')
101                     /* There isn't another character; no match.  */
102                     return FNM_NOMATCH;
103                   else
104                     /* One character of the string is consumed in matching
105                        this ? wildcard, so *??? won't match if there are
106                        less than three characters.  */
107                     ++n;
108                 }
109             }
110
111           if (c == '\0')
112             return 0;
113
114           {
115             char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
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 inverted.  */
127             register int nnot;
128
129             if (*n == '\0')
130               return FNM_NOMATCH;
131
132             if ((flags & FNM_PERIOD) && *n == '.' &&
133                 (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
134               return FNM_NOMATCH;
135
136             nnot = (*p == '!' || *p == '^');
137             if (nnot)
138               ++p;
139
140             c = *p++;
141             for (;;)
142               {
143                 register char cstart = c, cend = c;
144
145                 if (!(flags & FNM_NOESCAPE) && c == '\\')
146                   {
147                     if (*p == '\0')
148                       return FNM_NOMATCH;
149                     cstart = cend = *p++;
150                   }
151
152                 cstart = cend = FOLD (cstart);
153
154                 if (c == '\0')
155                   /* [ (unterminated) loses.  */
156                   return FNM_NOMATCH;
157
158                 c = *p++;
159                 c = FOLD (c);
160
161                 if ((flags & FNM_FILE_NAME) && c == '/')
162                   /* [/] can never match.  */
163                   return FNM_NOMATCH;
164
165                 if (c == '-' && *p != ']')
166                   {
167                     cend = *p++;
168                     if (!(flags & FNM_NOESCAPE) && cend == '\\')
169                       cend = *p++;
170                     if (cend == '\0')
171                       return FNM_NOMATCH;
172                     cend = FOLD (cend);
173
174                     c = *p++;
175                   }
176
177                 if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
178                   goto matched;
179
180                 if (c == ']')
181                   break;
182               }
183             if (!nnot)
184               return FNM_NOMATCH;
185             break;
186
187           matched:;
188             /* Skip the rest of the [...] that already matched.  */
189             while (c != ']')
190               {
191                 if (c == '\0')
192                   /* [... (unterminated) loses.  */
193                   return FNM_NOMATCH;
194
195                 c = *p++;
196                 if (!(flags & FNM_NOESCAPE) && c == '\\')
197                   {
198                     if (*p == '\0')
199                       return FNM_NOMATCH;
200                     /* XXX 1003.2d11 is unclear if this is right.  */
201                     ++p;
202                   }
203               }
204             if (nnot)
205               return FNM_NOMATCH;
206           }
207           break;
208
209         default:
210           if (c != FOLD ((unsigned char)*n))
211             return FNM_NOMATCH;
212         }
213
214       ++n;
215     }
216
217   if (*n == '\0')
218     return 0;
219
220   if ((flags & FNM_LEADING_DIR) && *n == '/')
221     /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
222     return 0;
223
224   return FNM_NOMATCH;
225
226 # undef FOLD
227 }
228
229 #endif  /* _LIBC or not __GNU_LIBRARY__.  */