]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/fnmatch.c
ebl add Error status in update volume=xxx status=yyyy
[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 # ifndef errno
21 extern int errno;
22 # endif
23
24 /* Match STRING against the filename pattern PATTERN, returning zero if
25    it matches, nonzero if not.  */
26 int
27 fnmatch (const char *pattern, const char *string, 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 ((c = *p++) != '\0')
36     {
37       c = FOLD (c);
38
39       switch (c)
40         {
41         case '?':
42           if (*n == '\0')
43             return FNM_NOMATCH;
44           else if ((flags & FNM_FILE_NAME) && IsPathSeparator(*n))
45             return FNM_NOMATCH;
46           else if ((flags & FNM_PERIOD) && *n == '.' &&
47                    (n == string || ((flags & FNM_FILE_NAME) && IsPathSeparator(n[-1]))))
48             return FNM_NOMATCH;
49           break;
50
51         case '\\':
52           if (!(flags & FNM_NOESCAPE))
53             {
54               c = *p++;
55               if (c == '\0')
56                 /* Trailing \ loses.  */
57                 return FNM_NOMATCH;
58               c = FOLD (c);
59             }
60           if (FOLD (*n) != c)
61             return FNM_NOMATCH;
62           break;
63
64         case '*':
65           if ((flags & FNM_PERIOD) && *n == '.' &&
66               (n == string || ((flags & FNM_FILE_NAME) && IsPathSeparator(n[-1]))))
67             return FNM_NOMATCH;
68
69           for (c = *p++; c == '?' || c == '*'; c = *p++)
70             {
71               if ((flags & FNM_FILE_NAME) && IsPathSeparator(*n))
72                 /* A slash does not match a wildcard under FNM_FILE_NAME.  */
73                 return FNM_NOMATCH;
74               else if (c == '?')
75                 {
76                   /* A ? needs to match one character.  */
77                   if (*n == '\0')
78                     /* There isn't another character; no match.  */
79                     return FNM_NOMATCH;
80                   else
81                     /* One character of the string is consumed in matching
82                        this ? wildcard, so *??? won't match if there are
83                        less than three characters.  */
84                     ++n;
85                 }
86             }
87
88           if (c == '\0')
89             return 0;
90
91           {
92             char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
93             c1 = FOLD (c1);
94             for (--p; *n != '\0'; ++n)
95               if ((c == '[' || FOLD ((unsigned char)*n) == c1) &&
96                   fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
97                 return 0;
98             return FNM_NOMATCH;
99           }
100
101         case '[':
102           {
103             /* Nonzero if the sense of the character class is inverted.  */
104             register int nnot;
105
106             if (*n == '\0')
107               return FNM_NOMATCH;
108
109             if ((flags & FNM_PERIOD) && *n == '.' &&
110                 (n == string || ((flags & FNM_FILE_NAME) && IsPathSeparator(n[-1]))))
111               return FNM_NOMATCH;
112
113             nnot = (*p == '!' || *p == '^');
114             if (nnot)
115               ++p;
116
117             c = *p++;
118             for (;;)
119               {
120                 register char cstart = c, cend = c;
121
122                 if (!(flags & FNM_NOESCAPE) && c == '\\')
123                   {
124                     if (*p == '\0')
125                       return FNM_NOMATCH;
126                     cstart = cend = *p++;
127                   }
128
129                 cstart = cend = FOLD (cstart);
130
131                 if (c == '\0')
132                   /* [ (unterminated) loses.  */
133                   return FNM_NOMATCH;
134
135                 c = *p++;
136                 c = FOLD (c);
137
138                 if ((flags & FNM_FILE_NAME) && IsPathSeparator(c))
139                   /* [/] can never match.  */
140                   return FNM_NOMATCH;
141
142                 if (c == '-' && *p != ']')
143                   {
144                     cend = *p++;
145                     if (!(flags & FNM_NOESCAPE) && cend == '\\')
146                       cend = *p++;
147                     if (cend == '\0')
148                       return FNM_NOMATCH;
149                     cend = FOLD (cend);
150
151                     c = *p++;
152                   }
153
154                 if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
155                   goto matched;
156
157                 if (c == ']')
158                   break;
159               }
160             if (!nnot)
161               return FNM_NOMATCH;
162             break;
163
164           matched:;
165             /* Skip the rest of the [...] that already matched.  */
166             while (c != ']')
167               {
168                 if (c == '\0')
169                   /* [... (unterminated) loses.  */
170                   return FNM_NOMATCH;
171
172                 c = *p++;
173                 if (!(flags & FNM_NOESCAPE) && c == '\\')
174                   {
175                     if (*p == '\0')
176                       return FNM_NOMATCH;
177                     /* XXX 1003.2d11 is unclear if this is right.  */
178                     ++p;
179                   }
180               }
181             if (nnot)
182               return FNM_NOMATCH;
183           }
184           break;
185
186         default:
187           if (c != FOLD (*n))
188             return FNM_NOMATCH;
189         }
190
191       ++n;
192     }
193
194   if (*n == '\0')
195     return 0;
196
197   if ((flags & FNM_LEADING_DIR) && IsPathSeparator(*n))
198     /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
199     return 0;
200
201   return FNM_NOMATCH;
202
203 # undef FOLD
204 }