Upgrade lib/fnmatch.[ch] to the latest from glibc-2.1.2 because the
[rsync/rsync.git] / lib / fnmatch.c
CommitLineData
c627d613
AT
1#include "../rsync.h"
2#ifndef HAVE_FNMATCH
3
9dce9b45
DD
4/* ----- THE FOLLOWING UP TO 'END' is glibc-2.1.2 posix/fnmatch.c
5 except for the part with the '#if 0' */
c627d613 6
9dce9b45
DD
7/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
8 This file is part of the GNU C Library.
c627d613 9
9dce9b45
DD
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.
c627d613 14
9dce9b45
DD
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.
c627d613 19
9dce9b45
DD
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. */
c627d613 24
9dce9b45
DD
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>
c627d613 40#else
9dce9b45 41# include <strings.h>
c627d613
AT
42#endif
43
9dce9b45
DD
44#if defined STDC_HEADERS || defined _LIBC
45# include <stdlib.h>
46#endif
c627d613 47
9dce9b45
DD
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
c627d613
AT
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
9dce9b45
DD
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')
c627d613 77#endif
9dce9b45
DD
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
129extern char *getenv ();
130# endif
131
132# ifndef errno
133extern int errno;
134# endif
c627d613
AT
135
136/* Match STRING against the filename pattern PATTERN, returning zero if
137 it matches, nonzero if not. */
9dce9b45
DD
138static int
139#ifdef _LIBC
140internal_function
141#endif
142internal_fnmatch (const char *pattern, const char *string,
143 int no_leading_period, int flags)
c627d613
AT
144{
145 register const char *p = pattern, *n = string;
9dce9b45 146 register unsigned char c;
c627d613 147
9dce9b45
DD
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
c627d613
AT
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;
9dce9b45 164 else if (*n == '/' && (flags & FNM_FILE_NAME))
c627d613 165 return FNM_NOMATCH;
9dce9b45
DD
166 else if (*n == '.' && no_leading_period
167 && (n == string
168 || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
c627d613
AT
169 return FNM_NOMATCH;
170 break;
171
172 case '\\':
173 if (!(flags & FNM_NOESCAPE))
174 {
175 c = *p++;
9dce9b45
DD
176 if (c == '\0')
177 /* Trailing \ loses. */
178 return FNM_NOMATCH;
c627d613
AT
179 c = FOLD (c);
180 }
9dce9b45 181 if (FOLD ((unsigned char) *n) != c)
c627d613
AT
182 return FNM_NOMATCH;
183 break;
184
185 case '*':
9dce9b45
DD
186 if (*n == '.' && no_leading_period
187 && (n == string
188 || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
c627d613
AT
189 return FNM_NOMATCH;
190
9dce9b45
DD
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 }
c627d613
AT
209
210 if (c == '\0')
9dce9b45
DD
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;
c627d613 219
9dce9b45
DD
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;
c627d613
AT
276
277 case '[':
278 {
279 /* Nonzero if the sense of the character class is inverted. */
9dce9b45 280 static int posixly_correct;
c627d613 281 register int not;
9dce9b45
DD
282 char cold;
283
284 if (posixly_correct == 0)
285 posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
c627d613
AT
286
287 if (*n == '\0')
288 return FNM_NOMATCH;
289
9dce9b45
DD
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. */
c627d613
AT
298 return FNM_NOMATCH;
299
9dce9b45 300 not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
c627d613
AT
301 if (not)
302 ++p;
303
304 c = *p++;
305 for (;;)
306 {
9dce9b45 307 unsigned char fn = FOLD ((unsigned char) *n);
c627d613
AT
308
309 if (!(flags & FNM_NOESCAPE) && c == '\\')
9dce9b45
DD
310 {
311 if (*p == '\0')
312 return FNM_NOMATCH;
313 c = FOLD ((unsigned char) *p);
314 ++p;
c627d613 315
9dce9b45
DD
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;
c627d613 359
9dce9b45
DD
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')
c627d613
AT
379 /* [ (unterminated) loses. */
380 return FNM_NOMATCH;
9dce9b45
DD
381 else
382 {
383 normal_bracket:
384 if (FOLD (c) == fn)
385 goto matched;
c627d613 386
9dce9b45
DD
387 cold = c;
388 c = *p++;
c627d613 389
9dce9b45
DD
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;
c627d613 398
9dce9b45
DD
399 if (cold <= fn && fn <= FOLD (cend))
400 goto matched;
c627d613 401
9dce9b45
DD
402 c = *p++;
403 }
c627d613
AT
404 }
405
c627d613
AT
406 if (c == ']')
407 break;
408 }
9dce9b45 409
c627d613
AT
410 if (!not)
411 return FNM_NOMATCH;
412 break;
413
9dce9b45 414 matched:
c627d613
AT
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 == '\\')
9dce9b45
DD
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 }
c627d613
AT
439 }
440 if (not)
441 return FNM_NOMATCH;
442 }
443 break;
444
445 default:
9dce9b45 446 if (c != FOLD ((unsigned char) *n))
c627d613
AT
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;
9dce9b45
DD
461
462# undef FOLD
c627d613
AT
463}
464
9dce9b45
DD
465
466int
467fnmatch (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
c627d613
AT
478#else /* HAVE_FNMATCH */
479void fnmatch_dummy(void) {}
480#endif