fnmatch.c revision 302408
118334Speter/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
218334Speter
318334SpeterNOTE: This source is derived from an old version taken from the GNU C
452284SobrienLibrary (glibc).
518334Speter
618334SpeterThis program is free software; you can redistribute it and/or modify it
718334Speterunder the terms of the GNU General Public License as published by the
818334SpeterFree Software Foundation; either version 2, or (at your option) any
918334Speterlater version.
1018334Speter
1118334SpeterThis program is distributed in the hope that it will be useful,
1218334Speterbut WITHOUT ANY WARRANTY; without even the implied warranty of
1318334SpeterMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1418334SpeterGNU General Public License for more details.
1518334Speter
1618334SpeterYou should have received a copy of the GNU General Public License
1718334Speteralong with this program; if not, write to the Free Software
1818334SpeterFoundation, 51 Franklin Street - Fifth Floor,
1918334SpeterBoston, MA 02110-1301, USA.  */
2018334Speter
2118334Speter#ifdef HAVE_CONFIG_H
2218334Speter#if defined (CONFIG_BROKETS)
2318334Speter/* We use <config.h> instead of "config.h" so that a compilation
2418334Speter   using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
2550397Sobrien   (which it would do because it found this file in $srcdir).  */
2652284Sobrien#include <config.h>
2718334Speter#else
2818334Speter#include "config.h"
2918334Speter#endif
3018334Speter#endif
3118334Speter
3218334Speter
3318334Speter#ifndef _GNU_SOURCE
3418334Speter#define _GNU_SOURCE
3518334Speter#endif
3618334Speter
3718334Speter/* This code to undef const added in libiberty.  */
3818334Speter#ifndef __STDC__
3952284Sobrien/* This is a separate conditional since some stdc systems
4018334Speter   reject `defined (const)'.  */
4152284Sobrien#ifndef const
4252284Sobrien#define const
4350397Sobrien#endif
4452284Sobrien#endif
4552284Sobrien
4652284Sobrien#include <errno.h>
4718334Speter#include <fnmatch.h>
4852284Sobrien#include <safe-ctype.h>
4918334Speter
5052284Sobrien/* Comment out all this code if we are using the GNU C Library, and are not
5152284Sobrien   actually compiling the library itself.  This code is part of the GNU C
5252284Sobrien   Library, but also included in many other GNU distributions.  Compiling
5352284Sobrien   and linking in this code is a waste when using the GNU C library
5452284Sobrien   (especially if it is a shared library).  Rather than having every GNU
5552284Sobrien   program understand `configure --with-gnu-libc' and omit the object files,
5652284Sobrien   it is simpler to just do this in the source for each such file.  */
5752284Sobrien
5818334Speter#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
5952284Sobrien
6052284Sobrien
6152284Sobrien#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
6252284Sobrienextern int errno;
6352284Sobrien#endif
6452284Sobrien
6552284Sobrien/* Match STRING against the filename pattern PATTERN, returning zero if
6652284Sobrien   it matches, nonzero if not.  */
6718334Speterint
6852284Sobrienfnmatch (const char *pattern, const char *string, int flags)
6918334Speter{
7052284Sobrien  register const char *p = pattern, *n = string;
7152284Sobrien  register unsigned char c;
7252284Sobrien
7352284Sobrien#define FOLD(c)	((flags & FNM_CASEFOLD) ? TOLOWER (c) : (c))
7418334Speter
7552284Sobrien  while ((c = *p++) != '\0')
7652284Sobrien    {
7718334Speter      c = FOLD (c);
7852284Sobrien
7952284Sobrien      switch (c)
8052284Sobrien	{
8152284Sobrien	case '?':
8252284Sobrien	  if (*n == '\0')
8318334Speter	    return FNM_NOMATCH;
8452284Sobrien	  else if ((flags & FNM_FILE_NAME) && *n == '/')
8552284Sobrien	    return FNM_NOMATCH;
8618334Speter	  else if ((flags & FNM_PERIOD) && *n == '.' &&
8752284Sobrien		   (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
8852284Sobrien	    return FNM_NOMATCH;
8952284Sobrien	  break;
9052284Sobrien
9152284Sobrien	case '\\':
9252284Sobrien	  if (!(flags & FNM_NOESCAPE))
9352284Sobrien	    {
9452284Sobrien	      c = *p++;
9552284Sobrien	      c = FOLD (c);
9652284Sobrien	    }
9752284Sobrien	  if (FOLD ((unsigned char)*n) != c)
9852284Sobrien	    return FNM_NOMATCH;
9952284Sobrien	  break;
10052284Sobrien
10152284Sobrien	case '*':
10252284Sobrien	  if ((flags & FNM_PERIOD) && *n == '.' &&
10352284Sobrien	      (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
10452284Sobrien	    return FNM_NOMATCH;
10552284Sobrien
10618334Speter	  for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
10752284Sobrien	    if (((flags & FNM_FILE_NAME) && *n == '/') ||
10818334Speter		(c == '?' && *n == '\0'))
10918334Speter	      return FNM_NOMATCH;
11018334Speter
11118334Speter	  if (c == '\0')
11218334Speter	    return 0;
11318334Speter
11418334Speter	  {
11518334Speter	    unsigned char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
11618334Speter	    c1 = FOLD (c1);
11718334Speter	    for (--p; *n != '\0'; ++n)
11818334Speter	      if ((c == '[' || FOLD ((unsigned char)*n) == c1) &&
11918334Speter		  fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
12018334Speter		return 0;
12118334Speter	    return FNM_NOMATCH;
12218334Speter	  }
12350397Sobrien
12452284Sobrien	case '[':
12552284Sobrien	  {
12618334Speter	    /* Nonzero if the sense of the character class is inverted.  */
12752284Sobrien	    register int negate;
12818334Speter
12918334Speter	    if (*n == '\0')
13018334Speter	      return FNM_NOMATCH;
13118334Speter
13252284Sobrien	    if ((flags & FNM_PERIOD) && *n == '.' &&
13352284Sobrien		(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
13418334Speter	      return FNM_NOMATCH;
13518334Speter
13618334Speter	    negate = (*p == '!' || *p == '^');
13718334Speter	    if (negate)
13818334Speter	      ++p;
13918334Speter
14018334Speter	    c = *p++;
14118334Speter	    for (;;)
14218334Speter	      {
14318334Speter		register unsigned char cstart = c, cend = c;
14418334Speter
14518334Speter		if (!(flags & FNM_NOESCAPE) && c == '\\')
14618334Speter		  cstart = cend = *p++;
14718334Speter
14818334Speter		cstart = cend = FOLD (cstart);
14918334Speter
15018334Speter		if (c == '\0')
15118334Speter		  /* [ (unterminated) loses.  */
15218334Speter		  return FNM_NOMATCH;
15318334Speter
15418334Speter		c = *p++;
15552284Sobrien		c = FOLD (c);
15618334Speter
15718334Speter		if ((flags & FNM_FILE_NAME) && c == '/')
15818334Speter		  /* [/] can never match.  */
15952284Sobrien		  return FNM_NOMATCH;
16018334Speter
16152284Sobrien		if (c == '-' && *p != ']')
16218334Speter		  {
16318334Speter		    cend = *p++;
16418334Speter		    if (!(flags & FNM_NOESCAPE) && cend == '\\')
16518334Speter		      cend = *p++;
16618334Speter		    if (cend == '\0')
16718334Speter		      return FNM_NOMATCH;
16818334Speter		    cend = FOLD (cend);
16950397Sobrien
17018334Speter		    c = *p++;
17152284Sobrien		  }
17218334Speter
17318334Speter		if (FOLD ((unsigned char)*n) >= cstart
17418334Speter		    && FOLD ((unsigned char)*n) <= cend)
17518334Speter		  goto matched;
17652284Sobrien
17718334Speter		if (c == ']')
17818334Speter		  break;
17918334Speter	      }
18018334Speter	    if (!negate)
18118334Speter	      return FNM_NOMATCH;
18218334Speter	    break;
18318334Speter
18418334Speter	  matched:;
18552284Sobrien	    /* Skip the rest of the [...] that already matched.  */
18618334Speter	    while (c != ']')
18718334Speter	      {
18852284Sobrien		if (c == '\0')
18918334Speter		  /* [... (unterminated) loses.  */
19018334Speter		  return FNM_NOMATCH;
19150397Sobrien
19250397Sobrien		c = *p++;
19352284Sobrien		if (!(flags & FNM_NOESCAPE) && c == '\\')
19452284Sobrien		  /* XXX 1003.2d11 is unclear if this is right.  */
19518334Speter		  ++p;
19618334Speter	      }
19718334Speter	    if (negate)
19818334Speter	      return FNM_NOMATCH;
19918334Speter	  }
20018334Speter	  break;
20118334Speter
20218334Speter	default:
20318334Speter	  if (c != FOLD ((unsigned char)*n))
20418334Speter	    return FNM_NOMATCH;
20518334Speter	}
20618334Speter
20718334Speter      ++n;
20818334Speter    }
20918334Speter
21018334Speter  if (*n == '\0')
21118334Speter    return 0;
21218334Speter
21318334Speter  if ((flags & FNM_LEADING_DIR) && *n == '/')
21418334Speter    /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
21518334Speter    return 0;
21618334Speter
21718334Speter  return FNM_NOMATCH;
21818334Speter}
21918334Speter
22018334Speter#endif	/* _LIBC or not __GNU_LIBRARY__.  */
22118334Speter