xref: /netbsd-src/external/gpl2/grep/dist/lib/fnmatch.c (revision a8fa202a6440953be7b92a8960a811bff58203f4)
1*a8fa202aSchristos /*	$NetBSD: fnmatch.c,v 1.1.1.1 2016/01/10 21:36:18 christos Exp $	*/
2*a8fa202aSchristos 
3*a8fa202aSchristos /* Copyright 1991, 1992, 1993, 1996, 1997, 2000 Free Software Foundation, Inc.
4*a8fa202aSchristos 
5*a8fa202aSchristos    This program is free software; you can redistribute it and/or modify
6*a8fa202aSchristos    it under the terms of the GNU General Public License as published by
7*a8fa202aSchristos    the Free Software Foundation; either version 2, or (at your option)
8*a8fa202aSchristos    any later version.
9*a8fa202aSchristos 
10*a8fa202aSchristos    This program is distributed in the hope that it will be useful,
11*a8fa202aSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
12*a8fa202aSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*a8fa202aSchristos    GNU General Public License for more details.
14*a8fa202aSchristos 
15*a8fa202aSchristos   You should have received a copy of the GNU General Public License
16*a8fa202aSchristos   along with this program; if not, write to the Free Software Foundation,
17*a8fa202aSchristos   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18*a8fa202aSchristos 
19*a8fa202aSchristos #if HAVE_CONFIG_H
20*a8fa202aSchristos # include <config.h>
21*a8fa202aSchristos #endif
22*a8fa202aSchristos 
23*a8fa202aSchristos /* Enable GNU extensions in fnmatch.h.  */
24*a8fa202aSchristos #ifndef _GNU_SOURCE
25*a8fa202aSchristos # define _GNU_SOURCE	1
26*a8fa202aSchristos #endif
27*a8fa202aSchristos 
28*a8fa202aSchristos #include <errno.h>
29*a8fa202aSchristos #include <fnmatch.h>
30*a8fa202aSchristos #include <ctype.h>
31*a8fa202aSchristos 
32*a8fa202aSchristos #if defined STDC_HEADERS || !defined isascii
33*a8fa202aSchristos # define IN_CTYPE_DOMAIN(c) 1
34*a8fa202aSchristos #else
35*a8fa202aSchristos # define IN_CTYPE_DOMAIN(c) isascii (c)
36*a8fa202aSchristos #endif
37*a8fa202aSchristos 
38*a8fa202aSchristos #define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
39*a8fa202aSchristos 
40*a8fa202aSchristos 
41*a8fa202aSchristos #ifndef errno
42*a8fa202aSchristos extern int errno;
43*a8fa202aSchristos #endif
44*a8fa202aSchristos 
45*a8fa202aSchristos /* Match STRING against the filename pattern PATTERN, returning zero if
46*a8fa202aSchristos    it matches, nonzero if not.  */
47*a8fa202aSchristos int
fnmatch(const char * pattern,const char * string,int flags)48*a8fa202aSchristos fnmatch (const char *pattern, const char *string, int flags)
49*a8fa202aSchristos {
50*a8fa202aSchristos   register const char *p = pattern, *n = string;
51*a8fa202aSchristos   register char c;
52*a8fa202aSchristos 
53*a8fa202aSchristos /* Note that this evaluates C many times.  */
54*a8fa202aSchristos #define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER ((unsigned char) (c)) \
55*a8fa202aSchristos                  ? tolower ((unsigned char) (c)) \
56*a8fa202aSchristos                  : (c))
57*a8fa202aSchristos 
58*a8fa202aSchristos   while ((c = *p++) != '\0')
59*a8fa202aSchristos     {
60*a8fa202aSchristos       c = FOLD (c);
61*a8fa202aSchristos 
62*a8fa202aSchristos       switch (c)
63*a8fa202aSchristos 	{
64*a8fa202aSchristos 	case '?':
65*a8fa202aSchristos 	  if (*n == '\0')
66*a8fa202aSchristos 	    return FNM_NOMATCH;
67*a8fa202aSchristos 	  else if ((flags & FNM_FILE_NAME) && *n == '/')
68*a8fa202aSchristos 	    return FNM_NOMATCH;
69*a8fa202aSchristos 	  else if ((flags & FNM_PERIOD) && *n == '.' &&
70*a8fa202aSchristos 		   (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
71*a8fa202aSchristos 	    return FNM_NOMATCH;
72*a8fa202aSchristos 	  break;
73*a8fa202aSchristos 
74*a8fa202aSchristos 	case '\\':
75*a8fa202aSchristos 	  if (!(flags & FNM_NOESCAPE))
76*a8fa202aSchristos 	    {
77*a8fa202aSchristos 	      c = *p++;
78*a8fa202aSchristos 	      if (c == '\0')
79*a8fa202aSchristos 		/* Trailing \ loses.  */
80*a8fa202aSchristos 		return FNM_NOMATCH;
81*a8fa202aSchristos 	      c = FOLD (c);
82*a8fa202aSchristos 	    }
83*a8fa202aSchristos 	  if (FOLD (*n) != c)
84*a8fa202aSchristos 	    return FNM_NOMATCH;
85*a8fa202aSchristos 	  break;
86*a8fa202aSchristos 
87*a8fa202aSchristos 	case '*':
88*a8fa202aSchristos 	  if ((flags & FNM_PERIOD) && *n == '.' &&
89*a8fa202aSchristos 	      (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
90*a8fa202aSchristos 	    return FNM_NOMATCH;
91*a8fa202aSchristos 
92*a8fa202aSchristos 	  for (c = *p++; c == '?' || c == '*'; c = *p++)
93*a8fa202aSchristos 	    {
94*a8fa202aSchristos 	      if (c == '?')
95*a8fa202aSchristos 		{
96*a8fa202aSchristos 		  /* A ? needs to match one character.  */
97*a8fa202aSchristos 		  if (*n == '\0' || (*n == '/' && (flags & FNM_FILE_NAME)))
98*a8fa202aSchristos 		    /* There isn't another character; no match.  */
99*a8fa202aSchristos 		    return FNM_NOMATCH;
100*a8fa202aSchristos 		  else
101*a8fa202aSchristos 		    /* One character of the string is consumed in matching
102*a8fa202aSchristos 		       this ? wildcard, so *??? won't match if there are
103*a8fa202aSchristos 		       less than three characters.  */
104*a8fa202aSchristos 		    ++n;
105*a8fa202aSchristos 		}
106*a8fa202aSchristos 	    }
107*a8fa202aSchristos 
108*a8fa202aSchristos 	  if (c == '\0')
109*a8fa202aSchristos 	    {
110*a8fa202aSchristos 	      if ((flags & (FNM_FILE_NAME | FNM_LEADING_DIR)) == FNM_FILE_NAME)
111*a8fa202aSchristos 		for (; *n != '\0'; n++)
112*a8fa202aSchristos 		  if (*n == '/')
113*a8fa202aSchristos 		    return FNM_NOMATCH;
114*a8fa202aSchristos 	      return 0;
115*a8fa202aSchristos 	    }
116*a8fa202aSchristos 
117*a8fa202aSchristos 	  {
118*a8fa202aSchristos 	    char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
119*a8fa202aSchristos 	    c1 = FOLD (c1);
120*a8fa202aSchristos 	    for (--p; *n != '\0'; ++n)
121*a8fa202aSchristos 	      if ((c == '[' || FOLD (*n) == c1) &&
122*a8fa202aSchristos 		  fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
123*a8fa202aSchristos 		return 0;
124*a8fa202aSchristos 	      else if (*n == '/' && (flags & FNM_FILE_NAME))
125*a8fa202aSchristos 		break;
126*a8fa202aSchristos 	    return FNM_NOMATCH;
127*a8fa202aSchristos 	  }
128*a8fa202aSchristos 
129*a8fa202aSchristos 	case '[':
130*a8fa202aSchristos 	  {
131*a8fa202aSchristos 	    /* Nonzero if the sense of the character class is inverted.  */
132*a8fa202aSchristos 	    register int not;
133*a8fa202aSchristos 
134*a8fa202aSchristos 	    if (*n == '\0')
135*a8fa202aSchristos 	      return FNM_NOMATCH;
136*a8fa202aSchristos 
137*a8fa202aSchristos 	    if ((flags & FNM_PERIOD) && *n == '.' &&
138*a8fa202aSchristos 		(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
139*a8fa202aSchristos 	      return FNM_NOMATCH;
140*a8fa202aSchristos 
141*a8fa202aSchristos 	    not = (*p == '!' || *p == '^');
142*a8fa202aSchristos 	    if (not)
143*a8fa202aSchristos 	      ++p;
144*a8fa202aSchristos 
145*a8fa202aSchristos 	    c = *p++;
146*a8fa202aSchristos 	    for (;;)
147*a8fa202aSchristos 	      {
148*a8fa202aSchristos 		register char cstart = c, cend = c;
149*a8fa202aSchristos 
150*a8fa202aSchristos 		if (!(flags & FNM_NOESCAPE) && c == '\\')
151*a8fa202aSchristos 		  {
152*a8fa202aSchristos 		    if (*p == '\0')
153*a8fa202aSchristos 		      return FNM_NOMATCH;
154*a8fa202aSchristos 		    cstart = cend = *p++;
155*a8fa202aSchristos 		  }
156*a8fa202aSchristos 
157*a8fa202aSchristos 		cstart = cend = FOLD (cstart);
158*a8fa202aSchristos 
159*a8fa202aSchristos 		if (c == '\0')
160*a8fa202aSchristos 		  /* [ (unterminated) loses.  */
161*a8fa202aSchristos 		  return FNM_NOMATCH;
162*a8fa202aSchristos 
163*a8fa202aSchristos 		c = *p++;
164*a8fa202aSchristos 		c = FOLD (c);
165*a8fa202aSchristos 
166*a8fa202aSchristos 		if ((flags & FNM_FILE_NAME) && c == '/')
167*a8fa202aSchristos 		  /* [/] can never match.  */
168*a8fa202aSchristos 		  return FNM_NOMATCH;
169*a8fa202aSchristos 
170*a8fa202aSchristos 		if (c == '-' && *p != ']')
171*a8fa202aSchristos 		  {
172*a8fa202aSchristos 		    cend = *p++;
173*a8fa202aSchristos 		    if (!(flags & FNM_NOESCAPE) && cend == '\\')
174*a8fa202aSchristos 		      cend = *p++;
175*a8fa202aSchristos 		    if (cend == '\0')
176*a8fa202aSchristos 		      return FNM_NOMATCH;
177*a8fa202aSchristos 		    cend = FOLD (cend);
178*a8fa202aSchristos 
179*a8fa202aSchristos 		    c = *p++;
180*a8fa202aSchristos 		  }
181*a8fa202aSchristos 
182*a8fa202aSchristos 		if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
183*a8fa202aSchristos 		  goto matched;
184*a8fa202aSchristos 
185*a8fa202aSchristos 		if (c == ']')
186*a8fa202aSchristos 		  break;
187*a8fa202aSchristos 	      }
188*a8fa202aSchristos 	    if (!not)
189*a8fa202aSchristos 	      return FNM_NOMATCH;
190*a8fa202aSchristos 	    break;
191*a8fa202aSchristos 
192*a8fa202aSchristos 	  matched:;
193*a8fa202aSchristos 	    /* Skip the rest of the [...] that already matched.  */
194*a8fa202aSchristos 	    while (c != ']')
195*a8fa202aSchristos 	      {
196*a8fa202aSchristos 		if (c == '\0')
197*a8fa202aSchristos 		  /* [... (unterminated) loses.  */
198*a8fa202aSchristos 		  return FNM_NOMATCH;
199*a8fa202aSchristos 
200*a8fa202aSchristos 		c = *p++;
201*a8fa202aSchristos 		if (!(flags & FNM_NOESCAPE) && c == '\\')
202*a8fa202aSchristos 		  {
203*a8fa202aSchristos 		    if (*p == '\0')
204*a8fa202aSchristos 		      return FNM_NOMATCH;
205*a8fa202aSchristos 		    /* XXX 1003.2d11 is unclear if this is right.  */
206*a8fa202aSchristos 		    ++p;
207*a8fa202aSchristos 		  }
208*a8fa202aSchristos 	      }
209*a8fa202aSchristos 	    if (not)
210*a8fa202aSchristos 	      return FNM_NOMATCH;
211*a8fa202aSchristos 	  }
212*a8fa202aSchristos 	  break;
213*a8fa202aSchristos 
214*a8fa202aSchristos 	default:
215*a8fa202aSchristos 	  if (c != FOLD (*n))
216*a8fa202aSchristos 	    return FNM_NOMATCH;
217*a8fa202aSchristos 	}
218*a8fa202aSchristos 
219*a8fa202aSchristos       ++n;
220*a8fa202aSchristos     }
221*a8fa202aSchristos 
222*a8fa202aSchristos   if (*n == '\0')
223*a8fa202aSchristos     return 0;
224*a8fa202aSchristos 
225*a8fa202aSchristos   if ((flags & FNM_LEADING_DIR) && *n == '/')
226*a8fa202aSchristos     /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
227*a8fa202aSchristos     return 0;
228*a8fa202aSchristos 
229*a8fa202aSchristos   return FNM_NOMATCH;
230*a8fa202aSchristos 
231*a8fa202aSchristos #undef FOLD
232*a8fa202aSchristos }
233