bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / strings / apr_fnmatch.c
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. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid[] = "@(#)fnmatch.c   8.2 (Berkeley) 4/16/94";
39 #endif /* LIBC_SCCS and not lint */
40
41 /*
42  * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
43  * Compares a filename or pathname to a pattern.
44  */
45 #ifndef WIN32
46 #include "apr_private.h"
47 #endif
48 #include "apr_fnmatch.h"
49 #include "apr_lib.h"
50 #include <string.h>
51 #if APR_HAVE_CTYPE_H
52 # include <ctype.h>
53 #endif
54
55 #define EOS     '\0'
56
57 static const char *rangematch(const char *, int, int);
58
59 APR_DECLARE(apr_status_t) apr_fnmatch(const char *pattern, const char *string, int flags)
60 {
61     const char *stringstart;
62     char c, test;
63
64     for (stringstart = string;;) {
65         switch (c = *pattern++) {
66         case EOS:
67             return (*string == EOS ? APR_SUCCESS : APR_FNM_NOMATCH);
68         case '?':
69             if (*string == EOS) {
70                 return (APR_FNM_NOMATCH);
71             }
72             if (*string == '/' && (flags & APR_FNM_PATHNAME)) {
73                 return (APR_FNM_NOMATCH);
74             }
75             if (*string == '.' && (flags & APR_FNM_PERIOD) &&
76                 (string == stringstart ||
77                  ((flags & APR_FNM_PATHNAME) && *(string - 1) == '/'))) {
78                 return (APR_FNM_NOMATCH);
79             }
80             ++string;
81             break;
82         case '*':
83             c = *pattern;
84             /* Collapse multiple stars. */
85             while (c == '*') {
86                 c = *++pattern;
87             }
88
89             if (*string == '.' && (flags & APR_FNM_PERIOD) &&
90                 (string == stringstart ||
91                  ((flags & APR_FNM_PATHNAME) && *(string - 1) == '/'))) {
92                 return (APR_FNM_NOMATCH);
93             }
94
95             /* Optimize for pattern with * at end or before /. */
96             if (c == EOS) {
97                 if (flags & APR_FNM_PATHNAME) {
98                     return (strchr(string, '/') == NULL ? APR_SUCCESS : APR_FNM_NOMATCH);
99                 }
100                 else {
101                     return (APR_SUCCESS);
102                 }
103             }
104             else if (c == '/' && flags & APR_FNM_PATHNAME) {
105                 if ((string = strchr(string, '/')) == NULL) {
106                     return (APR_FNM_NOMATCH);
107                 }
108                 break;
109             }
110
111             /* General case, use recursion. */
112             while ((test = *string) != EOS) {
113                 if (!apr_fnmatch(pattern, string, flags & ~APR_FNM_PERIOD)) {
114                     return (APR_SUCCESS);
115                 }
116                 if (test == '/' && flags & APR_FNM_PATHNAME) {
117                     break;
118                 }
119                 ++string;
120             }
121             return (APR_FNM_NOMATCH);
122         case '[':
123             if (*string == EOS) {
124                 return (APR_FNM_NOMATCH);
125             }
126             if (*string == '/' && flags & APR_FNM_PATHNAME) {
127                 return (APR_FNM_NOMATCH);
128             }
129             if (*string == '.' && (flags & APR_FNM_PERIOD) &&
130                 (string == stringstart ||
131                  ((flags & APR_FNM_PATHNAME) && *(string - 1) == '/'))) {
132                 return (APR_FNM_NOMATCH);
133             }
134             if ((pattern = rangematch(pattern, *string, flags)) == NULL) {
135                 return (APR_FNM_NOMATCH);
136             }
137             ++string;
138             break;
139         case '\\':
140             if (!(flags & APR_FNM_NOESCAPE)) {
141                 if ((c = *pattern++) == EOS) {
142                     c = '\\';
143                     --pattern;
144                 }
145             }
146             /* FALLTHROUGH */
147         default:
148             if (flags & APR_FNM_CASE_BLIND) {
149                 if (apr_tolower(c) != apr_tolower(*string)) {
150                     return (APR_FNM_NOMATCH);
151                 }
152             }
153             else if (c != *string) {
154                 return (APR_FNM_NOMATCH);
155             }
156             string++;
157             break;
158         }
159     /* NOTREACHED */
160     }
161 }
162
163 static const char *rangematch(const char *pattern, int test, int flags)
164 {
165     int negate, ok;
166     char c, c2;
167
168     /*
169      * A bracket expression starting with an unquoted circumflex
170      * character produces unspecified results (IEEE 1003.2-1992,
171      * 3.13.2).  This implementation treats it like '!', for
172      * consistency with the regular expression syntax.
173      * J.T. Conklin (conklin@ngai.kaleida.com)
174      */
175     if ((negate = (*pattern == '!' || *pattern == '^'))) {
176         ++pattern;
177     }
178
179     for (ok = 0; (c = *pattern++) != ']';) {
180         if (c == '\\' && !(flags & APR_FNM_NOESCAPE)) {
181             c = *pattern++;
182         }
183         if (c == EOS) {
184             return (NULL);
185         }
186         if (*pattern == '-' && (c2 = *(pattern + 1)) != EOS && c2 != ']') {
187             pattern += 2;
188             if (c2 == '\\' && !(flags & APR_FNM_NOESCAPE)) {
189                 c2 = *pattern++;
190             }
191             if (c2 == EOS) {
192                 return (NULL);
193             }
194             if ((c <= test && test <= c2)
195                 || ((flags & APR_FNM_CASE_BLIND)
196                     && ((apr_tolower(c) <= apr_tolower(test))
197                         && (apr_tolower(test) <= apr_tolower(c2))))) {
198                 ok = 1;
199             }
200         }
201         else if ((c == test)
202                  || ((flags & APR_FNM_CASE_BLIND)
203                      && (apr_tolower(c) == apr_tolower(test)))) {
204             ok = 1;
205         }
206     }
207     return (ok == negate ? NULL : pattern);
208 }
209
210
211 /* This function is an Apache addition */
212 /* return non-zero if pattern has any glob chars in it */
213 APR_DECLARE(int) apr_fnmatch_test(const char *pattern)
214 {
215     int nesting;
216
217     nesting = 0;
218     while (*pattern) {
219         switch (*pattern) {
220         case '?':
221         case '*':
222             return 1;
223
224         case '\\':
225             if (*pattern++ == '\0') {
226                 return 0;
227             }
228             break;
229
230         case '[':       /* '[' is only a glob if it has a matching ']' */
231             ++nesting;
232             break;
233
234         case ']':
235             if (nesting) {
236                 return 1;
237             }
238             break;
239         }
240         ++pattern;
241     }
242     return 0;
243 }
244
245 /* Deprecated */
246 APR_DECLARE(int) apr_is_fnmatch(const char *pattern)
247 {
248     return apr_fnmatch_test(pattern);
249 }