1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12 
13 /* @(#)fnmatch.c	1.4 02/02/10 eric */
14 /* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
15 
16 NOTE: The canonical source of this file is maintained with the GNU C Library.
17 Bugs can be reported to bug-glibc@prep.ai.mit.edu.
18 
19 This program is free software; you can redistribute it and/or modify it
20 under the terms of the GNU General Public License as published by the
21 Free Software Foundation; either version 2, or (at your option) any
22 later version.
23 
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27 GNU General Public License for more details.
28 
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include <errno.h>
38 #include <utypes.h>
39 #include "fnmatch.h"
40 
41 #ifndef	__STDC__
42 #define	const
43 #endif
44 
45 #ifndef FNM_FILE_NAME
46 #define	FNM_FILE_NAME	FNM_PATHNAME /* Preferred GNU name.  */
47 #endif
48 
49 #ifndef FNM_LEADING_DIR
50 #define	FNM_LEADING_DIR	(1 << 3) /* Ignore `/...' after a match.  */
51 #endif
52 
53 #ifndef FNM_CASEFOLD
54 #define	FNM_CASEFOLD	(1 << 4) /* Compare without regard to case.  */
55 #endif
56 
57 
58 #include <ctype.h>
59 
60 #if defined (STDC_HEADERS) || !defined (isascii)
61 #define ISASCII(c) 1
62 #else
63 #define ISASCII(c) isascii(c)
64 #endif
65 
66 #define ISUPPER(c) (ISASCII (c) && isupper (c))
67 
68 
69 /* Comment out all this code if we are using the GNU C Library, and are not
70    actually compiling the library itself.  This code is part of the GNU C
71    Library, but also included in many other GNU distributions.  Compiling
72    and linking in this code is a waste when using the GNU C library
73    (especially if it is a shared library).  Rather than having every GNU
74    program understand `configure --with-gnu-libc' and omit the object files,
75    it is simpler to just do this in the source for each such file.  */
76 
77 #if defined (_LIBC) || !defined (__GNU_LIBRARY__)
78 
79 
80 #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
81 extern int errno;
82 #endif
83 
84 /* Match STRING against the filename pattern PATTERN, returning zero if
85    it matches, nonzero if not.  */
86 int
fnmatch(const char * pattern,const char * string,int flags)87 fnmatch (const char *pattern, const char *string, int flags)
88 {
89   register const char *p = pattern, *n = string;
90   register char c;
91 
92 /* Note that this evalutes C many times.  */
93 #define FOLD(c)	((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
94 
95   while ((c = *p++) != '\0')
96     {
97       c = FOLD ((Uchar)c);
98 
99       switch (c)
100 	{
101 	case '?':
102 	  if (*n == '\0')
103 	    return FNM_NOMATCH;
104 	  else if ((flags & FNM_FILE_NAME) && *n == '/')
105 	    return FNM_NOMATCH;
106 	  else if ((flags & FNM_PERIOD) && *n == '.' &&
107 		   (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
108 	    return FNM_NOMATCH;
109 	  break;
110 
111 	case '\\':
112 	  if (!(flags & FNM_NOESCAPE))
113 	    {
114 	      c = *p++;
115 	      c = FOLD ((Uchar )c);
116 	    }
117 	  if (FOLD ((Uchar )*n) != c)
118 	    return FNM_NOMATCH;
119 	  break;
120 
121 	case '*':
122 	  if ((flags & FNM_PERIOD) && *n == '.' &&
123 	      (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
124 	    return FNM_NOMATCH;
125 
126 	  for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
127 	    if (((flags & FNM_FILE_NAME) && *n == '/') ||
128 		(c == '?' && *n == '\0'))
129 	      return FNM_NOMATCH;
130 
131 	  if (c == '\0')
132 	    return 0;
133 
134 	  {
135 	    char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
136 	    c1 = FOLD ((Uchar )c1);
137 	    for (--p; *n != '\0'; ++n)
138 	      if ((c == '[' || FOLD ((Uchar )*n) == c1) &&
139 		  fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
140 		return 0;
141 	    return FNM_NOMATCH;
142 	  }
143 
144 	case '[':
145 	  {
146 	    /* Nonzero if the sense of the character class is inverted.  */
147 	    register int not;
148 
149 	    if (*n == '\0')
150 	      return FNM_NOMATCH;
151 
152 	    if ((flags & FNM_PERIOD) && *n == '.' &&
153 		(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
154 	      return FNM_NOMATCH;
155 
156 	    not = (*p == '!' || *p == '^');
157 	    if (not)
158 	      ++p;
159 
160 	    c = *p++;
161 	    for (;;)
162 	      {
163 		register char cstart = c, cend = c;
164 
165 		if (!(flags & FNM_NOESCAPE) && c == '\\')
166 		  cstart = cend = *p++;
167 
168 		cstart = cend = FOLD ((Uchar)cstart);
169 
170 		if (c == '\0')
171 		  /* [ (unterminated) loses.  */
172 		  return FNM_NOMATCH;
173 
174 		c = *p++;
175 		c = FOLD ((Uchar)c);
176 
177 		if ((flags & FNM_FILE_NAME) && c == '/')
178 		  /* [/] can never match.  */
179 		  return FNM_NOMATCH;
180 
181 		if (c == '-' && *p != ']')
182 		  {
183 		    cend = *p++;
184 		    if (!(flags & FNM_NOESCAPE) && cend == '\\')
185 		      cend = *p++;
186 		    if (cend == '\0')
187 		      return FNM_NOMATCH;
188 		    cend = FOLD ((Uchar)cend);
189 
190 		    c = *p++;
191 		  }
192 
193 		if ((Uchar)FOLD((Uchar)*n) >= (Uchar)cstart && (Uchar)FOLD((Uchar)*n) <= (Uchar)cend)
194 		  goto matched;
195 
196 		if (c == ']')
197 		  break;
198 	      }
199 	    if (!not)
200 	      return FNM_NOMATCH;
201 	    break;
202 
203 	  matched:;
204 	    /* Skip the rest of the [...] that already matched.  */
205 	    while (c != ']')
206 	      {
207 		if (c == '\0')
208 		  /* [... (unterminated) loses.  */
209 		  return FNM_NOMATCH;
210 
211 		c = *p++;
212 		if (!(flags & FNM_NOESCAPE) && c == '\\')
213 		  /* XXX 1003.2d11 is unclear if this is right.  */
214 		  ++p;
215 	      }
216 	    if (not)
217 	      return FNM_NOMATCH;
218 	  }
219 	  break;
220 
221 	default:
222 	  if (c != FOLD ((Uchar)*n))
223 	    return FNM_NOMATCH;
224 	}
225 
226       ++n;
227     }
228 
229   if (*n == '\0')
230     return 0;
231 
232   if ((flags & FNM_LEADING_DIR) && *n == '/')
233     /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
234     return 0;
235 
236   return FNM_NOMATCH;
237 }
238 
239 #endif	/* _LIBC or not __GNU_LIBRARY__.  */
240