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