Use _IO_FILE_complete, not _IO_file_plus.
[kopensolaris-gnu/glibc.git] / posix / fnmatch.c
1 /* Copyright (C) 1991, 1992, 1993, 1996, 1997 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with this library; see the file COPYING.LIB.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 #if HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 /* Enable GNU extensions in fnmatch.h.  */
24 #ifndef _GNU_SOURCE
25 # define _GNU_SOURCE    1
26 #endif
27
28 #include <errno.h>
29 #include <fnmatch.h>
30 #include <ctype.h>
31
32
33 /* Comment out all this code if we are using the GNU C Library, and are not
34    actually compiling the library itself.  This code is part of the GNU C
35    Library, but also included in many other GNU distributions.  Compiling
36    and linking in this code is a waste when using the GNU C library
37    (especially if it is a shared library).  Rather than having every GNU
38    program understand `configure --with-gnu-libc' and omit the object files,
39    it is simpler to just do this in the source for each such file.  */
40
41 #if defined _LIBC || !defined __GNU_LIBRARY__
42
43
44 # if defined STDC_HEADERS || !defined isascii
45 #  define ISASCII(c) 1
46 # else
47 #  define ISASCII(c) isascii(c)
48 # endif
49
50 # define ISUPPER(c) (ISASCII (c) && isupper (c))
51
52
53 # ifndef errno
54 extern int errno;
55 # endif
56
57 /* Match STRING against the filename pattern PATTERN, returning zero if
58    it matches, nonzero if not.  */
59 int
60 fnmatch (pattern, string, flags)
61      const char *pattern;
62      const char *string;
63      int flags;
64 {
65   register const char *p = pattern, *n = string;
66   register char c;
67
68 /* Note that this evaluates C many times.  */
69 # define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
70
71   while ((c = *p++) != '\0')
72     {
73       c = FOLD (c);
74
75       switch (c)
76         {
77         case '?':
78           if (*n == '\0')
79             return FNM_NOMATCH;
80           else if ((flags & FNM_FILE_NAME) && *n == '/')
81             return FNM_NOMATCH;
82           else if ((flags & FNM_PERIOD) && *n == '.' &&
83                    (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
84             return FNM_NOMATCH;
85           break;
86
87         case '\\':
88           if (!(flags & FNM_NOESCAPE))
89             {
90               c = *p++;
91               if (c == '\0')
92                 /* Trailing \ loses.  */
93                 return FNM_NOMATCH;
94               c = FOLD (c);
95             }
96           if (FOLD (*n) != c)
97             return FNM_NOMATCH;
98           break;
99
100         case '*':
101           if ((flags & FNM_PERIOD) && *n == '.' &&
102               (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
103             return FNM_NOMATCH;
104
105           for (c = *p++; c == '?' || c == '*'; c = *p++)
106             {
107               if ((flags & FNM_FILE_NAME) && *n == '/')
108                 /* A slash does not match a wildcard under FNM_FILE_NAME.  */
109                 return FNM_NOMATCH;
110               else if (c == '?')
111                 {
112                   /* A ? needs to match one character.  */
113                   if (*n == '\0')
114                     /* There isn't another character; no match.  */
115                     return FNM_NOMATCH;
116                   else
117                     /* One character of the string is consumed in matching
118                        this ? wildcard, so *??? won't match if there are
119                        less than three characters.  */
120                     ++n;
121                 }
122             }
123
124           if (c == '\0')
125             return 0;
126
127           {
128             char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
129             c1 = FOLD (c1);
130             for (--p; *n != '\0'; ++n)
131               if ((c == '[' || FOLD (*n) == c1) &&
132                   fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
133                 return 0;
134             return FNM_NOMATCH;
135           }
136
137         case '[':
138           {
139             /* Nonzero if the sense of the character class is inverted.  */
140             register int not;
141
142             if (*n == '\0')
143               return FNM_NOMATCH;
144
145             if ((flags & FNM_PERIOD) && *n == '.' &&
146                 (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
147               return FNM_NOMATCH;
148
149             not = (*p == '!' || *p == '^');
150             if (not)
151               ++p;
152
153             c = *p++;
154             for (;;)
155               {
156                 register char cstart = c, cend = c;
157
158                 if (!(flags & FNM_NOESCAPE) && c == '\\')
159                   {
160                     if (*p == '\0')
161                       return FNM_NOMATCH;
162                     cstart = cend = *p++;
163                   }
164
165                 cstart = cend = FOLD (cstart);
166
167                 if (c == '\0')
168                   /* [ (unterminated) loses.  */
169                   return FNM_NOMATCH;
170
171                 c = *p++;
172                 c = FOLD (c);
173
174                 if ((flags & FNM_FILE_NAME) && c == '/')
175                   /* [/] can never match.  */
176                   return FNM_NOMATCH;
177
178                 if (c == '-' && *p != ']')
179                   {
180                     cend = *p++;
181                     if (!(flags & FNM_NOESCAPE) && cend == '\\')
182                       cend = *p++;
183                     if (cend == '\0')
184                       return FNM_NOMATCH;
185                     cend = FOLD (cend);
186
187                     c = *p++;
188                   }
189
190                 if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
191                   goto matched;
192
193                 if (c == ']')
194                   break;
195               }
196             if (!not)
197               return FNM_NOMATCH;
198             break;
199
200           matched:;
201             /* Skip the rest of the [...] that already matched.  */
202             while (c != ']')
203               {
204                 if (c == '\0')
205                   /* [... (unterminated) loses.  */
206                   return FNM_NOMATCH;
207
208                 c = *p++;
209                 if (!(flags & FNM_NOESCAPE) && c == '\\')
210                   {
211                     if (*p == '\0')
212                       return FNM_NOMATCH;
213                     /* XXX 1003.2d11 is unclear if this is right.  */
214                     ++p;
215                   }
216               }
217             if (not)
218               return FNM_NOMATCH;
219           }
220           break;
221
222         default:
223           if (c != FOLD (*n))
224             return FNM_NOMATCH;
225         }
226
227       ++n;
228     }
229
230   if (*n == '\0')
231     return 0;
232
233   if ((flags & FNM_LEADING_DIR) && *n == '/')
234     /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
235     return 0;
236
237   return FNM_NOMATCH;
238
239 # undef FOLD
240 }
241
242 #endif  /* _LIBC or not __GNU_LIBRARY__.  */