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