Update.
[platform/upstream/glibc.git] / posix / fnmatch.c
1 /* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 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 #if HAVE_STRING_H || defined _LIBC
33 # include <string.h>
34 #else
35 # include <strings.h>
36 #endif
37
38 #if defined STDC_HEADERS || defined _LIBC
39 # include <stdlib.h>
40 #endif
41
42 /* For platform which support the ISO C amendement 1 functionality we
43    support user defined character classes.  */
44 #if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
45 /* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
46 # include <wchar.h>
47 # include <wctype.h>
48 #endif
49
50 /* Comment out all this code if we are using the GNU C Library, and are not
51    actually compiling the library itself.  This code is part of the GNU C
52    Library, but also included in many other GNU distributions.  Compiling
53    and linking in this code is a waste when using the GNU C library
54    (especially if it is a shared library).  Rather than having every GNU
55    program understand `configure --with-gnu-libc' and omit the object files,
56    it is simpler to just do this in the source for each such file.  */
57
58 #if defined _LIBC || !defined __GNU_LIBRARY__
59
60
61 # if defined STDC_HEADERS || !defined isascii
62 #  define ISASCII(c) 1
63 # else
64 #  define ISASCII(c) isascii(c)
65 # endif
66
67 #ifdef isblank
68 # define ISBLANK(c) (ISASCII (c) && isblank (c))
69 #else
70 # define ISBLANK(c) ((c) == ' ' || (c) == '\t')
71 #endif
72 #ifdef isgraph
73 # define ISGRAPH(c) (ISASCII (c) && isgraph (c))
74 #else
75 # define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
76 #endif
77
78 #define ISPRINT(c) (ISASCII (c) && isprint (c))
79 #define ISDIGIT(c) (ISASCII (c) && isdigit (c))
80 #define ISALNUM(c) (ISASCII (c) && isalnum (c))
81 #define ISALPHA(c) (ISASCII (c) && isalpha (c))
82 #define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
83 #define ISLOWER(c) (ISASCII (c) && islower (c))
84 #define ISPUNCT(c) (ISASCII (c) && ispunct (c))
85 #define ISSPACE(c) (ISASCII (c) && isspace (c))
86 #define ISUPPER(c) (ISASCII (c) && isupper (c))
87 #define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
88
89 # define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
90
91 # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
92 /* The GNU C library provides support for user-defined character classes
93    and the functions from ISO C amendement 1.  */
94 #  ifdef CHARCLASS_NAME_MAX
95 #   define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
96 #  else
97 /* This shouldn't happen but some implementation might still have this
98    problem.  Use a reasonable default value.  */
99 #   define CHAR_CLASS_MAX_LENGTH 256
100 #  endif
101
102 #  ifdef _LIBC
103 #   define IS_CHAR_CLASS(string) __wctype (string)
104 #  else
105 #   define IS_CHAR_CLASS(string) wctype (string)
106 #  endif
107 # else
108 #  define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
109
110 #  define IS_CHAR_CLASS(string)                                               \
111    (STREQ (string, "alpha") || STREQ (string, "upper")                        \
112     || STREQ (string, "lower") || STREQ (string, "digit")                     \
113     || STREQ (string, "alnum") || STREQ (string, "xdigit")                    \
114     || STREQ (string, "space") || STREQ (string, "print")                     \
115     || STREQ (string, "punct") || STREQ (string, "graph")                     \
116     || STREQ (string, "cntrl") || STREQ (string, "blank"))
117 # endif
118
119 /* Avoid depending on library functions or files
120    whose names are inconsistent.  */
121
122 # if !defined _LIBC && !defined getenv
123 extern char *getenv ();
124 # endif
125
126 # ifndef errno
127 extern int errno;
128 # endif
129
130 /* Match STRING against the filename pattern PATTERN, returning zero if
131    it matches, nonzero if not.  */
132 static int
133 internal_function
134 internal_fnmatch (const char *pattern, const char *string,
135                   int no_leading_period, int flags)
136 {
137   register const char *p = pattern, *n = string;
138   register unsigned char c;
139
140 /* Note that this evaluates C many times.  */
141 # ifdef _LIBC
142 #  define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
143 # else
144 #  define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
145 # endif
146
147   while ((c = *p++) != '\0')
148     {
149       c = FOLD (c);
150
151       switch (c)
152         {
153         case '?':
154           if (*n == '\0')
155             return FNM_NOMATCH;
156           else if (*n == '/' && (flags & FNM_FILE_NAME))
157             return FNM_NOMATCH;
158           else if (*n == '.' && no_leading_period)
159             return FNM_NOMATCH;
160           break;
161
162         case '\\':
163           if (!(flags & FNM_NOESCAPE))
164             {
165               c = *p++;
166               if (c == '\0')
167                 /* Trailing \ loses.  */
168                 return FNM_NOMATCH;
169               c = FOLD (c);
170             }
171           if (FOLD ((unsigned char) *n) != c)
172             return FNM_NOMATCH;
173           break;
174
175         case '*':
176           if (*n == '.' && no_leading_period)
177             return FNM_NOMATCH;
178
179           for (c = *p++; c == '?' || c == '*'; c = *p++)
180             {
181               if (*n == '/' && (flags & FNM_FILE_NAME))
182                 /* A slash does not match a wildcard under FNM_FILE_NAME.  */
183                 return FNM_NOMATCH;
184               else if (c == '?')
185                 {
186                   /* A ? needs to match one character.  */
187                   if (*n == '\0')
188                     /* There isn't another character; no match.  */
189                     return FNM_NOMATCH;
190                   else
191                     /* One character of the string is consumed in matching
192                        this ? wildcard, so *??? won't match if there are
193                        less than three characters.  */
194                     ++n;
195                 }
196             }
197
198           if (c == '\0')
199             /* The wildcard(s) is/are the last element of the pattern.
200                If the name is a file name and contains another slash
201                this does mean it cannot match.  */
202             return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL
203                     ? FNM_NOMATCH : 0);
204           else
205             {
206               const char *endp;
207
208               if (!(flags & FNM_FILE_NAME) || (endp = strchr (n, '/')) == NULL)
209                 endp = strchr (n, '\0');
210
211               if (c == '[')
212                 {
213                   for (--p; n < endp; ++n)
214                     if (internal_fnmatch (p, n,
215                                           (n == string) && no_leading_period,
216                                           ((flags & FNM_FILE_NAME)
217                                            ? flags : (flags & ~FNM_PERIOD)))
218                         == 0)
219                       return 0;
220                 }
221               else if (c == '/' && (flags & FNM_FILE_NAME))
222                 {
223                   while (*n != '\0' && *n != '/')
224                     ++n;
225                   if (*n == '/'
226                       && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
227                                             flags) == 0))
228                     return 0;
229                 }
230               else
231                 {
232                   if (c == '\\' && !(flags & FNM_NOESCAPE))
233                     c = *p;
234                   c = FOLD (c);
235                   for (--p; n < endp; ++n)
236                     if (FOLD ((unsigned char) *n) == c
237                         && (internal_fnmatch (p, n,
238                                               ((n == string)
239                                                && no_leading_period),
240                                               ((flags & FNM_FILE_NAME)
241                                                ? flags
242                                                : (flags & ~FNM_PERIOD)))
243                             == 0))
244                       return 0;
245                 }
246             }
247
248           /* If we come here no match is possible with the wildcard.  */
249           return FNM_NOMATCH;
250
251         case '[':
252           {
253             /* Nonzero if the sense of the character class is inverted.  */
254             static int posixly_correct;
255             register int not;
256             char cold;
257
258             if (posixly_correct == 0)
259               posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
260
261             if (*n == '\0')
262               return FNM_NOMATCH;
263
264             if (*n == '.' && no_leading_period)
265               return FNM_NOMATCH;
266
267             if (*n == '/' && (flags & FNM_FILE_NAME))
268               /* `/' cannot be matched.  */
269               return FNM_NOMATCH;
270
271             not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
272             if (not)
273               ++p;
274
275             c = *p++;
276             for (;;)
277               {
278                 unsigned char fn = FOLD ((unsigned char) *n);
279
280                 if (!(flags & FNM_NOESCAPE) && c == '\\')
281                   {
282                     if (*p == '\0')
283                       return FNM_NOMATCH;
284                     c = FOLD ((unsigned char) *p);
285                     ++p;
286
287                     if (c == fn)
288                       goto matched;
289                   }
290                 else if (c == '[' && *p == ':')
291                   {
292                     /* Leave room for the null.  */
293                     char str[CHAR_CLASS_MAX_LENGTH + 1];
294                     size_t c1 = 0;
295 # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
296                     wctype_t wt;
297 # endif
298
299                     for (;;)
300                       {
301                         if (c1 == CHAR_CLASS_MAX_LENGTH)
302                           /* The name is too long and therefore the pattern
303                              is ill-formed.  */
304                           return FNM_NOMATCH;
305
306                         c = *++p;
307                         if (c == ':' && p[1] == ']')
308                           {
309                             p += 2;
310                             break;
311                           }
312                         if (c < 'a' || c >= 'z')
313                           {
314                             /* This cannot possibly be a character class name.
315                                Match it as a normal range.  */
316                             --p;
317                             c = '[';
318                             goto normal_bracket;
319                           }
320                         str[c1++] = c;
321                       }
322                     str[c1] = '\0';
323
324 # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
325                     wt = IS_CHAR_CLASS (str);
326                     if (wt == 0)
327                       /* Invalid character class name.  */
328                       return FNM_NOMATCH;
329
330                     if (__iswctype (__btowc ((unsigned char) *n), wt))
331                       goto matched;
332 # else
333                     if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n))
334                         || (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n))
335                         || (STREQ (str, "blank") && ISBLANK ((unsigned char) *n))
336                         || (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n))
337                         || (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n))
338                         || (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n))
339                         || (STREQ (str, "lower") && ISLOWER ((unsigned char) *n))
340                         || (STREQ (str, "print") && ISPRINT ((unsigned char) *n))
341                         || (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n))
342                         || (STREQ (str, "space") && ISSPACE ((unsigned char) *n))
343                         || (STREQ (str, "upper") && ISUPPER ((unsigned char) *n))
344                         || (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n)))
345                       goto matched;
346 # endif
347                   }
348                 else if (c == '\0')
349                   /* [ (unterminated) loses.  */
350                   return FNM_NOMATCH;
351                 else
352                   {
353                   normal_bracket:
354                     if (FOLD (c) == fn)
355                       goto matched;
356
357                     cold = c;
358                     c = *p++;
359
360                     if (c == '-' && *p != ']')
361                       {
362                         /* It is a range.  */
363                         unsigned char cend = *p++;
364                         if (!(flags & FNM_NOESCAPE) && cend == '\\')
365                           cend = *p++;
366                         if (cend == '\0')
367                           return FNM_NOMATCH;
368
369                         if (cold <= fn && fn <= FOLD (cend))
370                           goto matched;
371
372                         c = *p++;
373                       }
374                   }
375
376                 if (c == ']')
377                   break;
378               }
379
380             if (!not)
381               return FNM_NOMATCH;
382             break;
383
384           matched:
385             /* Skip the rest of the [...] that already matched.  */
386             while (c != ']')
387               {
388                 if (c == '\0')
389                   /* [... (unterminated) loses.  */
390                   return FNM_NOMATCH;
391
392                 c = *p++;
393                 if (!(flags & FNM_NOESCAPE) && c == '\\')
394                   {
395                     if (*p == '\0')
396                       return FNM_NOMATCH;
397                     /* XXX 1003.2d11 is unclear if this is right.  */
398                     ++p;
399                   }
400                 else if (c == '[' && *p == ':')
401                   {
402                     do
403                       if (*++p == '\0')
404                         return FNM_NOMATCH;
405                     while (*p != ':' || p[1] == ']');
406                     p += 2;
407                     c = *p;
408                   }
409               }
410             if (not)
411               return FNM_NOMATCH;
412           }
413           break;
414
415         default:
416           if (c != FOLD ((unsigned char) *n))
417             return FNM_NOMATCH;
418         }
419
420       ++n;
421     }
422
423   if (*n == '\0')
424     return 0;
425
426   if ((flags & FNM_LEADING_DIR) && *n == '/')
427     /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
428     return 0;
429
430   return FNM_NOMATCH;
431
432 # undef FOLD
433 }
434
435
436 int
437 fnmatch (pattern, string, flags)
438      const char *pattern;
439      const char *string;
440      int flags;
441 {
442   return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
443 }
444
445 #endif  /* _LIBC or not __GNU_LIBRARY__.  */