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