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 platform which support the ISO C amendement 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 amendement 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
123extern char *getenv ();
124# endif
125
126# ifndef errno
127extern int errno;
128# endif
129
130/* This function doesn't exist on most systems.  */
131
132# if !defined HAVE___STRCHRNUL && !defined _LIBC
133static 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.  */
153static int internal_fnmatch __P ((const char *pattern, const char *string,
154				  int no_leading_period, int flags))
155     internal_function;
156static int
157internal_function
158internal_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
479int
480fnmatch (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__.  */
489