xref: /netbsd-src/external/gpl3/binutils/dist/libiberty/fnmatch.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1*cb63e24eSchristos /* Copyright (C) 1991-2024 Free Software Foundation, Inc.
22a6b7db3Sskrll 
32a6b7db3Sskrll NOTE: This source is derived from an old version taken from the GNU C
42a6b7db3Sskrll Library (glibc).
52a6b7db3Sskrll 
62a6b7db3Sskrll This program is free software; you can redistribute it and/or modify it
72a6b7db3Sskrll under the terms of the GNU General Public License as published by the
82a6b7db3Sskrll Free Software Foundation; either version 2, or (at your option) any
92a6b7db3Sskrll later version.
102a6b7db3Sskrll 
112a6b7db3Sskrll This program is distributed in the hope that it will be useful,
122a6b7db3Sskrll but WITHOUT ANY WARRANTY; without even the implied warranty of
132a6b7db3Sskrll MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
142a6b7db3Sskrll GNU General Public License for more details.
152a6b7db3Sskrll 
162a6b7db3Sskrll You should have received a copy of the GNU General Public License
172a6b7db3Sskrll along with this program; if not, write to the Free Software
182a6b7db3Sskrll Foundation, 51 Franklin Street - Fifth Floor,
192a6b7db3Sskrll Boston, MA 02110-1301, USA.  */
202a6b7db3Sskrll 
212a6b7db3Sskrll #ifdef HAVE_CONFIG_H
222a6b7db3Sskrll #if defined (CONFIG_BROKETS)
232a6b7db3Sskrll /* We use <config.h> instead of "config.h" so that a compilation
242a6b7db3Sskrll    using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
252a6b7db3Sskrll    (which it would do because it found this file in $srcdir).  */
262a6b7db3Sskrll #include <config.h>
272a6b7db3Sskrll #else
282a6b7db3Sskrll #include "config.h"
292a6b7db3Sskrll #endif
302a6b7db3Sskrll #endif
312a6b7db3Sskrll 
322a6b7db3Sskrll 
332a6b7db3Sskrll #ifndef _GNU_SOURCE
342a6b7db3Sskrll #define _GNU_SOURCE
352a6b7db3Sskrll #endif
362a6b7db3Sskrll 
372a6b7db3Sskrll /* This code to undef const added in libiberty.  */
382a6b7db3Sskrll #ifndef __STDC__
392a6b7db3Sskrll /* This is a separate conditional since some stdc systems
402a6b7db3Sskrll    reject `defined (const)'.  */
412a6b7db3Sskrll #ifndef const
422a6b7db3Sskrll #define const
432a6b7db3Sskrll #endif
442a6b7db3Sskrll #endif
452a6b7db3Sskrll 
462a6b7db3Sskrll #include <errno.h>
472a6b7db3Sskrll #include <fnmatch.h>
482a6b7db3Sskrll #include <safe-ctype.h>
492a6b7db3Sskrll 
502a6b7db3Sskrll /* Comment out all this code if we are using the GNU C Library, and are not
512a6b7db3Sskrll    actually compiling the library itself.  This code is part of the GNU C
522a6b7db3Sskrll    Library, but also included in many other GNU distributions.  Compiling
532a6b7db3Sskrll    and linking in this code is a waste when using the GNU C library
542a6b7db3Sskrll    (especially if it is a shared library).  Rather than having every GNU
552a6b7db3Sskrll    program understand `configure --with-gnu-libc' and omit the object files,
562a6b7db3Sskrll    it is simpler to just do this in the source for each such file.  */
572a6b7db3Sskrll 
582a6b7db3Sskrll #if defined (_LIBC) || !defined (__GNU_LIBRARY__)
592a6b7db3Sskrll 
602a6b7db3Sskrll 
612a6b7db3Sskrll #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
622a6b7db3Sskrll extern int errno;
632a6b7db3Sskrll #endif
642a6b7db3Sskrll 
652a6b7db3Sskrll /* Match STRING against the filename pattern PATTERN, returning zero if
662a6b7db3Sskrll    it matches, nonzero if not.  */
672a6b7db3Sskrll int
fnmatch(const char * pattern,const char * string,int flags)682a6b7db3Sskrll fnmatch (const char *pattern, const char *string, int flags)
692a6b7db3Sskrll {
702a6b7db3Sskrll   register const char *p = pattern, *n = string;
712a6b7db3Sskrll   register unsigned char c;
722a6b7db3Sskrll 
732a6b7db3Sskrll #define FOLD(c)	((flags & FNM_CASEFOLD) ? TOLOWER (c) : (c))
742a6b7db3Sskrll 
752a6b7db3Sskrll   while ((c = *p++) != '\0')
762a6b7db3Sskrll     {
772a6b7db3Sskrll       c = FOLD (c);
782a6b7db3Sskrll 
792a6b7db3Sskrll       switch (c)
802a6b7db3Sskrll 	{
812a6b7db3Sskrll 	case '?':
822a6b7db3Sskrll 	  if (*n == '\0')
832a6b7db3Sskrll 	    return FNM_NOMATCH;
842a6b7db3Sskrll 	  else if ((flags & FNM_FILE_NAME) && *n == '/')
852a6b7db3Sskrll 	    return FNM_NOMATCH;
862a6b7db3Sskrll 	  else if ((flags & FNM_PERIOD) && *n == '.' &&
872a6b7db3Sskrll 		   (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
882a6b7db3Sskrll 	    return FNM_NOMATCH;
892a6b7db3Sskrll 	  break;
902a6b7db3Sskrll 
912a6b7db3Sskrll 	case '\\':
922a6b7db3Sskrll 	  if (!(flags & FNM_NOESCAPE))
932a6b7db3Sskrll 	    {
942a6b7db3Sskrll 	      c = *p++;
952a6b7db3Sskrll 	      c = FOLD (c);
962a6b7db3Sskrll 	    }
972a6b7db3Sskrll 	  if (FOLD ((unsigned char)*n) != c)
982a6b7db3Sskrll 	    return FNM_NOMATCH;
992a6b7db3Sskrll 	  break;
1002a6b7db3Sskrll 
1012a6b7db3Sskrll 	case '*':
1022a6b7db3Sskrll 	  if ((flags & FNM_PERIOD) && *n == '.' &&
1032a6b7db3Sskrll 	      (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
1042a6b7db3Sskrll 	    return FNM_NOMATCH;
1052a6b7db3Sskrll 
1062a6b7db3Sskrll 	  for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
1072a6b7db3Sskrll 	    if (((flags & FNM_FILE_NAME) && *n == '/') ||
1082a6b7db3Sskrll 		(c == '?' && *n == '\0'))
1092a6b7db3Sskrll 	      return FNM_NOMATCH;
1102a6b7db3Sskrll 
1112a6b7db3Sskrll 	  if (c == '\0')
1122a6b7db3Sskrll 	    return 0;
1132a6b7db3Sskrll 
1142a6b7db3Sskrll 	  {
1152a6b7db3Sskrll 	    unsigned char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
1162a6b7db3Sskrll 	    c1 = FOLD (c1);
1172a6b7db3Sskrll 	    for (--p; *n != '\0'; ++n)
1182a6b7db3Sskrll 	      if ((c == '[' || FOLD ((unsigned char)*n) == c1) &&
1192a6b7db3Sskrll 		  fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
1202a6b7db3Sskrll 		return 0;
1212a6b7db3Sskrll 	    return FNM_NOMATCH;
1222a6b7db3Sskrll 	  }
1232a6b7db3Sskrll 
1242a6b7db3Sskrll 	case '[':
1252a6b7db3Sskrll 	  {
1262a6b7db3Sskrll 	    /* Nonzero if the sense of the character class is inverted.  */
1272a6b7db3Sskrll 	    register int negate;
1282a6b7db3Sskrll 
1292a6b7db3Sskrll 	    if (*n == '\0')
1302a6b7db3Sskrll 	      return FNM_NOMATCH;
1312a6b7db3Sskrll 
1322a6b7db3Sskrll 	    if ((flags & FNM_PERIOD) && *n == '.' &&
1332a6b7db3Sskrll 		(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
1342a6b7db3Sskrll 	      return FNM_NOMATCH;
1352a6b7db3Sskrll 
1362a6b7db3Sskrll 	    negate = (*p == '!' || *p == '^');
1372a6b7db3Sskrll 	    if (negate)
1382a6b7db3Sskrll 	      ++p;
1392a6b7db3Sskrll 
1402a6b7db3Sskrll 	    c = *p++;
1412a6b7db3Sskrll 	    for (;;)
1422a6b7db3Sskrll 	      {
1432a6b7db3Sskrll 		register unsigned char cstart = c, cend = c;
1442a6b7db3Sskrll 
1452a6b7db3Sskrll 		if (!(flags & FNM_NOESCAPE) && c == '\\')
1462a6b7db3Sskrll 		  cstart = cend = *p++;
1472a6b7db3Sskrll 
1482a6b7db3Sskrll 		cstart = cend = FOLD (cstart);
1492a6b7db3Sskrll 
1502a6b7db3Sskrll 		if (c == '\0')
1512a6b7db3Sskrll 		  /* [ (unterminated) loses.  */
1522a6b7db3Sskrll 		  return FNM_NOMATCH;
1532a6b7db3Sskrll 
1542a6b7db3Sskrll 		c = *p++;
1552a6b7db3Sskrll 		c = FOLD (c);
1562a6b7db3Sskrll 
1572a6b7db3Sskrll 		if ((flags & FNM_FILE_NAME) && c == '/')
1582a6b7db3Sskrll 		  /* [/] can never match.  */
1592a6b7db3Sskrll 		  return FNM_NOMATCH;
1602a6b7db3Sskrll 
1612a6b7db3Sskrll 		if (c == '-' && *p != ']')
1622a6b7db3Sskrll 		  {
1632a6b7db3Sskrll 		    cend = *p++;
1642a6b7db3Sskrll 		    if (!(flags & FNM_NOESCAPE) && cend == '\\')
1652a6b7db3Sskrll 		      cend = *p++;
1662a6b7db3Sskrll 		    if (cend == '\0')
1672a6b7db3Sskrll 		      return FNM_NOMATCH;
1682a6b7db3Sskrll 		    cend = FOLD (cend);
1692a6b7db3Sskrll 
1702a6b7db3Sskrll 		    c = *p++;
1712a6b7db3Sskrll 		  }
1722a6b7db3Sskrll 
1732a6b7db3Sskrll 		if (FOLD ((unsigned char)*n) >= cstart
1742a6b7db3Sskrll 		    && FOLD ((unsigned char)*n) <= cend)
1752a6b7db3Sskrll 		  goto matched;
1762a6b7db3Sskrll 
1772a6b7db3Sskrll 		if (c == ']')
1782a6b7db3Sskrll 		  break;
1792a6b7db3Sskrll 	      }
1802a6b7db3Sskrll 	    if (!negate)
1812a6b7db3Sskrll 	      return FNM_NOMATCH;
1822a6b7db3Sskrll 	    break;
1832a6b7db3Sskrll 
1842a6b7db3Sskrll 	  matched:;
1852a6b7db3Sskrll 	    /* Skip the rest of the [...] that already matched.  */
1862a6b7db3Sskrll 	    while (c != ']')
1872a6b7db3Sskrll 	      {
1882a6b7db3Sskrll 		if (c == '\0')
1892a6b7db3Sskrll 		  /* [... (unterminated) loses.  */
1902a6b7db3Sskrll 		  return FNM_NOMATCH;
1912a6b7db3Sskrll 
1922a6b7db3Sskrll 		c = *p++;
1932a6b7db3Sskrll 		if (!(flags & FNM_NOESCAPE) && c == '\\')
1942a6b7db3Sskrll 		  /* XXX 1003.2d11 is unclear if this is right.  */
1952a6b7db3Sskrll 		  ++p;
1962a6b7db3Sskrll 	      }
1972a6b7db3Sskrll 	    if (negate)
1982a6b7db3Sskrll 	      return FNM_NOMATCH;
1992a6b7db3Sskrll 	  }
2002a6b7db3Sskrll 	  break;
2012a6b7db3Sskrll 
2022a6b7db3Sskrll 	default:
2032a6b7db3Sskrll 	  if (c != FOLD ((unsigned char)*n))
2042a6b7db3Sskrll 	    return FNM_NOMATCH;
2052a6b7db3Sskrll 	}
2062a6b7db3Sskrll 
2072a6b7db3Sskrll       ++n;
2082a6b7db3Sskrll     }
2092a6b7db3Sskrll 
2102a6b7db3Sskrll   if (*n == '\0')
2112a6b7db3Sskrll     return 0;
2122a6b7db3Sskrll 
2132a6b7db3Sskrll   if ((flags & FNM_LEADING_DIR) && *n == '/')
2142a6b7db3Sskrll     /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
2152a6b7db3Sskrll     return 0;
2162a6b7db3Sskrll 
2172a6b7db3Sskrll   return FNM_NOMATCH;
2182a6b7db3Sskrll }
2192a6b7db3Sskrll 
2202a6b7db3Sskrll #endif	/* _LIBC or not __GNU_LIBRARY__.  */
221