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