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