• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 License
15 along with this library; see the file COPYING.LIB.  If not, write to the Free
16 Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
17 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
123 extern char *getenv ();
124 # endif
125 
126 # ifndef errno
127 extern int errno;
128 # endif
129 
130 /* This function doesn't exist on most systems.  */
131 
132 # if !defined HAVE___STRCHRNUL && !defined _LIBC
133 static char *
__strchrnul(s,c)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.  */
153 static int internal_fnmatch __P ((const char *pattern, const char *string,
154 				  int no_leading_period, int flags))
155      internal_function;
156 static int
157 internal_function
internal_fnmatch(pattern,string,no_leading_period,flags)158 internal_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 
479 int
fnmatch(pattern,string,flags)480 fnmatch (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