1 /*
2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Guido van Rossum.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /* OpenBSD: fnmatch.c,v 1.6 1998/03/19 00:29:59 millert */
34
35 /*
36 * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
37 * Compares a filename or pathname to a pattern.
38 */
39
40 /* Define SYS to use the system fnmatch() rather than ours */
41 /* #define SYS 1 */
42
43 #include "include/bareos.h"
44 #ifdef SYS
45 #include <fnmatch.h>
46 #else
47 #include "fnmatch.h"
48 #endif
49
50 #undef EOS
51 #define EOS '\0'
52
53 #define RANGE_MATCH 1
54 #define RANGE_NOMATCH 0
55 #define RANGE_ERROR (-1)
56
57 /* Limit of recursion during matching attempts. */
58 #define FNM_MAX_RECUR 64
59
60 #define ISSET(x, y) ((x) & (y))
61 #define FOLD(c) ((flags & FNM_CASEFOLD) && B_ISUPPER(c) ? tolower(c) : (c))
62
63 static int Rangematch(const char*, char, int, char**);
64 static int r_fnmatch(const char*, const char*, int, int);
65
66 #ifdef SYS
xfnmatch(const char * pattern,const char * string,int flags)67 int xfnmatch(const char* pattern, const char* string, int flags)
68 #else
69 int fnmatch(const char* pattern, const char* string, int flags)
70 #endif
71 {
72 int e;
73
74 e = r_fnmatch(pattern, string, flags, FNM_MAX_RECUR);
75 if (e == -1) { /* Too much recursion */
76 e = FNM_NOMATCH;
77 }
78 return (e);
79 }
80
r_fnmatch(const char * pattern,const char * string,int flags,int recur)81 static int r_fnmatch(const char* pattern,
82 const char* string,
83 int flags,
84 int recur)
85 {
86 const char* stringstart;
87 char* newp;
88 char c, test;
89 int e;
90
91 if (recur-- <= 0) { return (-1); }
92
93 stringstart = string;
94 for (;;) {
95 switch (c = *pattern++) {
96 case EOS:
97 if (ISSET(flags, FNM_LEADING_DIR) && IsPathSeparator(*string))
98 return (0);
99 return (*string == EOS ? 0 : FNM_NOMATCH);
100 case '?':
101 if (*string == EOS) return (FNM_NOMATCH);
102 if (IsPathSeparator(*string) && ISSET(flags, FNM_PATHNAME))
103 return (FNM_NOMATCH);
104 if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
105 (string == stringstart ||
106 (ISSET(flags, FNM_PATHNAME) && IsPathSeparator(*(string - 1)))))
107 return (FNM_NOMATCH);
108 ++string;
109 break;
110 case '*':
111 c = *pattern;
112 /* Collapse multiple stars. */
113 while (c == '*') { c = *++pattern; }
114
115 if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
116 (string == stringstart ||
117 (ISSET(flags, FNM_PATHNAME) && IsPathSeparator(*(string - 1))))) {
118 return (FNM_NOMATCH);
119 }
120
121 /* Optimize for pattern with * at end or before /. */
122 if (c == EOS) {
123 if (ISSET(flags, FNM_PATHNAME)) {
124 return (ISSET(flags, FNM_LEADING_DIR) || strchr(string, '/') == NULL
125 ? 0
126 : FNM_NOMATCH);
127 } else {
128 return (0);
129 }
130 } else if (IsPathSeparator(c) && ISSET(flags, FNM_PATHNAME)) {
131 if ((string = strchr(string, '/')) == NULL) return (FNM_NOMATCH);
132 break;
133 }
134
135 /* General case, use recursion. */
136 while ((test = *string) != EOS) {
137 e = r_fnmatch(pattern, string, flags & ~FNM_PERIOD, recur);
138 if (e != FNM_NOMATCH) { /* can be NOMATCH, -1 or MATCH */
139 return (e);
140 }
141 if (test == '/' && ISSET(flags, FNM_PATHNAME)) { break; }
142 ++string;
143 }
144 return (FNM_NOMATCH);
145 case '[':
146 if (*string == EOS) return (FNM_NOMATCH);
147 if (IsPathSeparator(*string) && ISSET(flags, FNM_PATHNAME))
148 return (FNM_NOMATCH);
149 if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
150 (string == stringstart ||
151 (ISSET(flags, FNM_PATHNAME) && IsPathSeparator(*(string - 1)))))
152 return (FNM_NOMATCH);
153
154 switch (Rangematch(pattern, *string, flags, &newp)) {
155 case RANGE_ERROR:
156 /* not a good range, treat as normal text */
157 goto normal;
158 case RANGE_MATCH:
159 pattern = newp;
160 break;
161 case RANGE_NOMATCH:
162 return (FNM_NOMATCH);
163 }
164 ++string;
165 break;
166
167 case '\\':
168 if (!ISSET(flags, FNM_NOESCAPE)) {
169 if ((c = *pattern++) == EOS) {
170 c = '\\';
171 --pattern;
172 }
173 }
174 /* FALLTHROUGH */
175 default:
176 normal:
177 if (FOLD(c) != FOLD(*string)) { return (FNM_NOMATCH); }
178 ++string;
179 break;
180 }
181 }
182 /* NOTREACHED */
183 }
184
Rangematch(const char * pattern,char test,int flags,char ** newp)185 static int Rangematch(const char* pattern, char test, int flags, char** newp)
186 {
187 int negate, ok;
188 char c, c2;
189
190 /*
191 * A bracket expression starting with an unquoted circumflex
192 * character produces unspecified results (IEEE 1003.2-1992,
193 * 3.13.2). This implementation treats it like '!', for
194 * consistency with the regular expression syntax.
195 * J.T. Conklin (conklin@ngai.kaleida.com)
196 */
197 if ((negate = (*pattern == '!' || *pattern == '^'))) ++pattern;
198
199 test = FOLD(test);
200
201 /*
202 * A right bracket shall lose its special meaning and represent
203 * itself in a bracket expression if it occurs first in the list.
204 * -- POSIX.2 2.8.3.2
205 */
206 ok = 0;
207 c = *pattern++;
208 do {
209 if (c == '\\' && !ISSET(flags, FNM_NOESCAPE)) c = *pattern++;
210 if (c == EOS) return (RANGE_ERROR);
211 if (c == '/' && ISSET(flags, FNM_PATHNAME)) return (RANGE_NOMATCH);
212 c = FOLD(c);
213 if (*pattern == '-' && (c2 = *(pattern + 1)) != EOS && c2 != ']') {
214 pattern += 2;
215 if (c2 == '\\' && !ISSET(flags, FNM_NOESCAPE)) c2 = *pattern++;
216 if (c2 == EOS) return (RANGE_ERROR);
217 c2 = FOLD(c2);
218 if (c <= test && test <= c2) ok = 1;
219 } else if (c == test)
220 ok = 1;
221 } while ((c = *pattern++) != ']');
222
223 *newp = (char*)pattern;
224 return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
225 }
226