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