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