]> Pileus Git - ~andy/gtk/blob - gtk/fnmatch.c
198363fc84963923ce6bbd9887fc7b6aeef7987c
[~andy/gtk] / gtk / fnmatch.c
1 /* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2 of the License, or (at your option) any later version.
7  *
8  * This library 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 GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16  * Boston, MA 02111-1307, USA.
17  */
18
19 /*
20  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
21  * file for a list of people on the GTK+ Team.  See the ChangeLog
22  * files for a list of changes.  These files are distributed with
23  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <errno.h>
31 #include <ctype.h> /* tolower */
32
33 /* Added for GTK. We need to make sure that all constants are defined
34  * to properly compile this file */
35 #ifndef _GNU_SOURCE
36 #define _GNU_SOURCE
37 #endif
38 #include "fnmatch.h"
39
40 /* We need glib.h for G_DIR_SEPARATOR and G_OS_WIN32 */
41 #include <glib.h>
42
43
44 /* Comment out all this code if we are using the GNU C Library, and are not
45    actually compiling the library itself.  This code is part of the GNU C
46    Library, but also included in many other GNU distributions.  Compiling
47    and linking in this code is a waste when using the GNU C library
48    (especially if it is a shared library).  Rather than having every GNU
49    program understand `configure --with-gnu-libc' and omit the object files,
50    it is simpler to just do this in the source for each such file.  */
51
52 #if defined (_LIBC) || !defined (__GNU_LIBRARY__)
53
54 #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
55 extern int errno;
56 #endif
57
58 /* Match STRING against the filename pattern PATTERN, returning zero if
59    it matches, nonzero if not.  */
60 int
61 fnmatch (pattern, string, flags)
62      const char *pattern;
63      const char *string;
64      int flags;
65 {
66   register const char *p = pattern, *n = string;
67   register char c;
68
69 /* Note that this evalutes C many times.  */
70 #if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
71 #define FOLD(c) ((flags & FNM_CASEFOLD) && isupper ((unsigned char )(c)) ? tolower ((unsigned char)(c)) : (c))
72 #else
73 #define FOLD(c) (tolower ((unsigned char)(c)))
74 #endif
75
76   while ((c = *p++) != '\0')
77     {
78       c = FOLD (c);
79
80       switch (c)
81         {
82         case '?':
83           if (*n == '\0')
84             return FNM_NOMATCH;
85           else if ((flags & FNM_FILE_NAME) && *n == G_DIR_SEPARATOR)
86             return FNM_NOMATCH;
87           else if ((flags & FNM_PERIOD) && *n == '.' &&
88                    (n == string || ((flags & FNM_FILE_NAME) && n[-1] == G_DIR_SEPARATOR)))
89             return FNM_NOMATCH;
90           break;
91 #ifndef G_OS_WIN32
92         case '\\':
93           if (!(flags & FNM_NOESCAPE))
94             {
95               c = *p++;
96               c = FOLD (c);
97             }
98           if (FOLD (*n) != c)
99             return FNM_NOMATCH;
100           break;
101 #endif
102         case '*':
103           if ((flags & FNM_PERIOD) && *n == '.' &&
104               (n == string || ((flags & FNM_FILE_NAME) && n[-1] == G_DIR_SEPARATOR)))
105             return FNM_NOMATCH;
106
107           for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
108             if (((flags & FNM_FILE_NAME) && *n == G_DIR_SEPARATOR) ||
109                 (c == '?' && *n == '\0'))
110               return FNM_NOMATCH;
111
112           if (c == '\0')
113             return 0;
114
115           {
116 #ifndef G_OS_WIN32
117             char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
118 #else
119             char c1 = c;
120 #endif
121             c1 = FOLD (c1);
122             for (--p; *n != '\0'; ++n)
123               if ((c == '[' || FOLD (*n) == c1) &&
124                   fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
125                 return 0;
126             return FNM_NOMATCH;
127           }
128
129         case '[':
130           {
131             /* Nonzero if the sense of the character class is inverted.  */
132             register int not;
133
134             if (*n == '\0')
135               return FNM_NOMATCH;
136
137             if ((flags & FNM_PERIOD) && *n == '.' &&
138                 (n == string || ((flags & FNM_FILE_NAME) && n[-1] == G_DIR_SEPARATOR)))
139               return FNM_NOMATCH;
140
141             not = (*p == '!' || *p == '^');
142             if (not)
143               ++p;
144
145             c = *p++;
146             for (;;)
147               {
148                 register char cstart = c, cend = c;
149 #ifndef G_OS_WIN32
150                 if (!(flags & FNM_NOESCAPE) && c == '\\')
151                   cstart = cend = *p++;
152 #endif
153                 cstart = cend = FOLD (cstart);
154
155                 if (c == '\0')
156                   /* [ (unterminated) loses.  */
157                   return FNM_NOMATCH;
158
159                 c = *p++;
160                 c = FOLD (c);
161
162                 if ((flags & FNM_FILE_NAME) && c == G_DIR_SEPARATOR)
163                   /* [/] can never match.  */
164                   return FNM_NOMATCH;
165
166                 if (c == '-' && *p != ']')
167                   {
168                     cend = *p++;
169 #ifndef G_OS_WIN32
170                     if (!(flags & FNM_NOESCAPE) && cend == '\\')
171                       cend = *p++;
172 #endif
173                     if (cend == '\0')
174                       return FNM_NOMATCH;
175                     cend = FOLD (cend);
176
177                     c = *p++;
178                   }
179
180                 if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
181                   goto matched;
182
183                 if (c == ']')
184                   break;
185               }
186             if (!not)
187               return FNM_NOMATCH;
188             break;
189
190           matched:;
191             /* Skip the rest of the [...] that already matched.  */
192             while (c != ']')
193               {
194                 if (c == '\0')
195                   /* [... (unterminated) loses.  */
196                   return FNM_NOMATCH;
197
198                 c = *p++;
199 #ifndef G_OS_WIN32
200                 if (!(flags & FNM_NOESCAPE) && c == '\\')
201                   /* XXX 1003.2d11 is unclear if this is right.  */
202                   ++p;
203 #endif
204               }
205             if (not)
206               return FNM_NOMATCH;
207           }
208           break;
209
210         default:
211           if (c != FOLD (*n))
212             return FNM_NOMATCH;
213         }
214
215       ++n;
216     }
217
218   if (*n == '\0')
219     return 0;
220
221   if ((flags & FNM_LEADING_DIR) && *n == G_DIR_SEPARATOR)
222     /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
223     return 0;
224
225   return FNM_NOMATCH;
226 }
227
228 #endif  /* _LIBC or not __GNU_LIBRARY__.  */