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