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