xref: /openbsd-src/gnu/lib/libiberty/src/fnmatch.c (revision 150b7e42cfa21e6546d96ae514ca23e80d970ac7)
100bf4279Sespie /* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
200bf4279Sespie 
3f5dd06f4Sespie NOTE: This source is derived from an old version taken from the GNU C
4f5dd06f4Sespie Library (glibc).
500bf4279Sespie 
600bf4279Sespie This program is free software; you can redistribute it and/or modify it
700bf4279Sespie under the terms of the GNU General Public License as published by the
800bf4279Sespie Free Software Foundation; either version 2, or (at your option) any
900bf4279Sespie later version.
1000bf4279Sespie 
1100bf4279Sespie This program is distributed in the hope that it will be useful,
1200bf4279Sespie but WITHOUT ANY WARRANTY; without even the implied warranty of
1300bf4279Sespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1400bf4279Sespie GNU General Public License for more details.
1500bf4279Sespie 
1600bf4279Sespie You should have received a copy of the GNU General Public License
1700bf4279Sespie along with this program; if not, write to the Free Software
18*150b7e42Smiod Foundation, 51 Franklin Street - Fifth Floor,
19*150b7e42Smiod Boston, MA 02110-1301, USA.  */
2000bf4279Sespie 
2100bf4279Sespie #ifdef HAVE_CONFIG_H
2200bf4279Sespie #if defined (CONFIG_BROKETS)
2300bf4279Sespie /* We use <config.h> instead of "config.h" so that a compilation
2400bf4279Sespie    using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
2500bf4279Sespie    (which it would do because it found this file in $srcdir).  */
2600bf4279Sespie #include <config.h>
2700bf4279Sespie #else
2800bf4279Sespie #include "config.h"
2900bf4279Sespie #endif
3000bf4279Sespie #endif
3100bf4279Sespie 
3200bf4279Sespie 
3300bf4279Sespie #ifndef _GNU_SOURCE
3400bf4279Sespie #define _GNU_SOURCE
3500bf4279Sespie #endif
3600bf4279Sespie 
3700bf4279Sespie /* This code to undef const added in libiberty.  */
3800bf4279Sespie #ifndef __STDC__
3900bf4279Sespie /* This is a separate conditional since some stdc systems
4000bf4279Sespie    reject `defined (const)'.  */
4100bf4279Sespie #ifndef const
4200bf4279Sespie #define const
4300bf4279Sespie #endif
4400bf4279Sespie #endif
4500bf4279Sespie 
4600bf4279Sespie #include <errno.h>
4700bf4279Sespie #include <fnmatch.h>
48f5dd06f4Sespie #include <safe-ctype.h>
4900bf4279Sespie 
5000bf4279Sespie /* Comment out all this code if we are using the GNU C Library, and are not
5100bf4279Sespie    actually compiling the library itself.  This code is part of the GNU C
5200bf4279Sespie    Library, but also included in many other GNU distributions.  Compiling
5300bf4279Sespie    and linking in this code is a waste when using the GNU C library
5400bf4279Sespie    (especially if it is a shared library).  Rather than having every GNU
5500bf4279Sespie    program understand `configure --with-gnu-libc' and omit the object files,
5600bf4279Sespie    it is simpler to just do this in the source for each such file.  */
5700bf4279Sespie 
5800bf4279Sespie #if defined (_LIBC) || !defined (__GNU_LIBRARY__)
5900bf4279Sespie 
6000bf4279Sespie 
6100bf4279Sespie #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
6200bf4279Sespie extern int errno;
6300bf4279Sespie #endif
6400bf4279Sespie 
6500bf4279Sespie /* Match STRING against the filename pattern PATTERN, returning zero if
6600bf4279Sespie    it matches, nonzero if not.  */
6700bf4279Sespie int
fnmatch(const char * pattern,const char * string,int flags)68*150b7e42Smiod fnmatch (const char *pattern, const char *string, int flags)
6900bf4279Sespie {
7000bf4279Sespie   register const char *p = pattern, *n = string;
7100bf4279Sespie   register unsigned char c;
7200bf4279Sespie 
73f5dd06f4Sespie #define FOLD(c)	((flags & FNM_CASEFOLD) ? TOLOWER (c) : (c))
7400bf4279Sespie 
7500bf4279Sespie   while ((c = *p++) != '\0')
7600bf4279Sespie     {
7700bf4279Sespie       c = FOLD (c);
7800bf4279Sespie 
7900bf4279Sespie       switch (c)
8000bf4279Sespie 	{
8100bf4279Sespie 	case '?':
8200bf4279Sespie 	  if (*n == '\0')
8300bf4279Sespie 	    return FNM_NOMATCH;
8400bf4279Sespie 	  else if ((flags & FNM_FILE_NAME) && *n == '/')
8500bf4279Sespie 	    return FNM_NOMATCH;
8600bf4279Sespie 	  else if ((flags & FNM_PERIOD) && *n == '.' &&
8700bf4279Sespie 		   (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
8800bf4279Sespie 	    return FNM_NOMATCH;
8900bf4279Sespie 	  break;
9000bf4279Sespie 
9100bf4279Sespie 	case '\\':
9200bf4279Sespie 	  if (!(flags & FNM_NOESCAPE))
9300bf4279Sespie 	    {
9400bf4279Sespie 	      c = *p++;
9500bf4279Sespie 	      c = FOLD (c);
9600bf4279Sespie 	    }
9700bf4279Sespie 	  if (FOLD ((unsigned char)*n) != c)
9800bf4279Sespie 	    return FNM_NOMATCH;
9900bf4279Sespie 	  break;
10000bf4279Sespie 
10100bf4279Sespie 	case '*':
10200bf4279Sespie 	  if ((flags & FNM_PERIOD) && *n == '.' &&
10300bf4279Sespie 	      (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
10400bf4279Sespie 	    return FNM_NOMATCH;
10500bf4279Sespie 
10600bf4279Sespie 	  for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
10700bf4279Sespie 	    if (((flags & FNM_FILE_NAME) && *n == '/') ||
10800bf4279Sespie 		(c == '?' && *n == '\0'))
10900bf4279Sespie 	      return FNM_NOMATCH;
11000bf4279Sespie 
11100bf4279Sespie 	  if (c == '\0')
11200bf4279Sespie 	    return 0;
11300bf4279Sespie 
11400bf4279Sespie 	  {
11500bf4279Sespie 	    unsigned char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
11600bf4279Sespie 	    c1 = FOLD (c1);
11700bf4279Sespie 	    for (--p; *n != '\0'; ++n)
11800bf4279Sespie 	      if ((c == '[' || FOLD ((unsigned char)*n) == c1) &&
11900bf4279Sespie 		  fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
12000bf4279Sespie 		return 0;
12100bf4279Sespie 	    return FNM_NOMATCH;
12200bf4279Sespie 	  }
12300bf4279Sespie 
12400bf4279Sespie 	case '[':
12500bf4279Sespie 	  {
12600bf4279Sespie 	    /* Nonzero if the sense of the character class is inverted.  */
127*150b7e42Smiod 	    register int negate;
12800bf4279Sespie 
12900bf4279Sespie 	    if (*n == '\0')
13000bf4279Sespie 	      return FNM_NOMATCH;
13100bf4279Sespie 
13200bf4279Sespie 	    if ((flags & FNM_PERIOD) && *n == '.' &&
13300bf4279Sespie 		(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
13400bf4279Sespie 	      return FNM_NOMATCH;
13500bf4279Sespie 
136*150b7e42Smiod 	    negate = (*p == '!' || *p == '^');
137*150b7e42Smiod 	    if (negate)
13800bf4279Sespie 	      ++p;
13900bf4279Sespie 
14000bf4279Sespie 	    c = *p++;
14100bf4279Sespie 	    for (;;)
14200bf4279Sespie 	      {
14300bf4279Sespie 		register unsigned char cstart = c, cend = c;
14400bf4279Sespie 
14500bf4279Sespie 		if (!(flags & FNM_NOESCAPE) && c == '\\')
14600bf4279Sespie 		  cstart = cend = *p++;
14700bf4279Sespie 
14800bf4279Sespie 		cstart = cend = FOLD (cstart);
14900bf4279Sespie 
15000bf4279Sespie 		if (c == '\0')
15100bf4279Sespie 		  /* [ (unterminated) loses.  */
15200bf4279Sespie 		  return FNM_NOMATCH;
15300bf4279Sespie 
15400bf4279Sespie 		c = *p++;
15500bf4279Sespie 		c = FOLD (c);
15600bf4279Sespie 
15700bf4279Sespie 		if ((flags & FNM_FILE_NAME) && c == '/')
15800bf4279Sespie 		  /* [/] can never match.  */
15900bf4279Sespie 		  return FNM_NOMATCH;
16000bf4279Sespie 
16100bf4279Sespie 		if (c == '-' && *p != ']')
16200bf4279Sespie 		  {
16300bf4279Sespie 		    cend = *p++;
16400bf4279Sespie 		    if (!(flags & FNM_NOESCAPE) && cend == '\\')
16500bf4279Sespie 		      cend = *p++;
16600bf4279Sespie 		    if (cend == '\0')
16700bf4279Sespie 		      return FNM_NOMATCH;
16800bf4279Sespie 		    cend = FOLD (cend);
16900bf4279Sespie 
17000bf4279Sespie 		    c = *p++;
17100bf4279Sespie 		  }
17200bf4279Sespie 
17300bf4279Sespie 		if (FOLD ((unsigned char)*n) >= cstart
17400bf4279Sespie 		    && FOLD ((unsigned char)*n) <= cend)
17500bf4279Sespie 		  goto matched;
17600bf4279Sespie 
17700bf4279Sespie 		if (c == ']')
17800bf4279Sespie 		  break;
17900bf4279Sespie 	      }
180*150b7e42Smiod 	    if (!negate)
18100bf4279Sespie 	      return FNM_NOMATCH;
18200bf4279Sespie 	    break;
18300bf4279Sespie 
18400bf4279Sespie 	  matched:;
18500bf4279Sespie 	    /* Skip the rest of the [...] that already matched.  */
18600bf4279Sespie 	    while (c != ']')
18700bf4279Sespie 	      {
18800bf4279Sespie 		if (c == '\0')
18900bf4279Sespie 		  /* [... (unterminated) loses.  */
19000bf4279Sespie 		  return FNM_NOMATCH;
19100bf4279Sespie 
19200bf4279Sespie 		c = *p++;
19300bf4279Sespie 		if (!(flags & FNM_NOESCAPE) && c == '\\')
19400bf4279Sespie 		  /* XXX 1003.2d11 is unclear if this is right.  */
19500bf4279Sespie 		  ++p;
19600bf4279Sespie 	      }
197*150b7e42Smiod 	    if (negate)
19800bf4279Sespie 	      return FNM_NOMATCH;
19900bf4279Sespie 	  }
20000bf4279Sespie 	  break;
20100bf4279Sespie 
20200bf4279Sespie 	default:
20300bf4279Sespie 	  if (c != FOLD ((unsigned char)*n))
20400bf4279Sespie 	    return FNM_NOMATCH;
20500bf4279Sespie 	}
20600bf4279Sespie 
20700bf4279Sespie       ++n;
20800bf4279Sespie     }
20900bf4279Sespie 
21000bf4279Sespie   if (*n == '\0')
21100bf4279Sespie     return 0;
21200bf4279Sespie 
21300bf4279Sespie   if ((flags & FNM_LEADING_DIR) && *n == '/')
21400bf4279Sespie     /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
21500bf4279Sespie     return 0;
21600bf4279Sespie 
21700bf4279Sespie   return FNM_NOMATCH;
21800bf4279Sespie }
21900bf4279Sespie 
22000bf4279Sespie #endif	/* _LIBC or not __GNU_LIBRARY__.  */
221