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