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