Annotation of embedaddon/sudo/compat/fnmatch.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 2008, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
3: * Copyright (c) 1989, 1993, 1994
4: * The Regents of the University of California. All rights reserved.
5: *
6: * This code is derived from software contributed to Berkeley by
7: * Guido van Rossum.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: */
33:
34: /*
35: * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
36: * Compares a filename or pathname to a pattern.
37: */
38:
39: #include <config.h>
40:
41: #include <sys/types.h>
42:
43: #include <stdio.h>
44: #include <ctype.h>
45: #ifdef HAVE_STRING_H
46: # include <string.h>
47: #endif /* HAVE_STRING_H */
48: #ifdef HAVE_STRINGS_H
49: # include <strings.h>
50: #endif /* HAVE_STRINGS_H */
51:
52: #include "missing.h"
53: #include "compat/charclass.h"
54: #include "compat/fnmatch.h"
55:
56: #undef EOS
57: #define EOS '\0'
58:
59: #define RANGE_MATCH 1
60: #define RANGE_NOMATCH 0
61: #define RANGE_ERROR (-1)
62:
63: #if defined(LIBC_SCCS) && !defined(lint)
64: __unused static const char rcsid[] = "$OpenBSD: fnmatch.c,v 1.6 1998/03/19 00:29:59 millert Exp $";
65: #endif /* LIBC_SCCS and not lint */
66:
67: static int rangematch(const char *, int, int, char **);
68: static int classmatch(const char *, int, int, const char **);
69:
70: int
71: rpl_fnmatch(const char *pattern, const char *string, int flags)
72: {
73: const char *stringstart;
74: char *newp;
75: char c, test;
76:
77: for (stringstart = string;;)
78: switch (c = *pattern++) {
79: case EOS:
80: if (ISSET(flags, FNM_LEADING_DIR) && *string == '/')
81: return 0;
82: return *string == EOS ? 0 : FNM_NOMATCH;
83: case '?':
84: if (*string == EOS)
85: return FNM_NOMATCH;
86: if (*string == '/' && ISSET(flags, FNM_PATHNAME))
87: return FNM_NOMATCH;
88: if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
89: (string == stringstart ||
90: (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
91: return FNM_NOMATCH;
92: ++string;
93: break;
94: case '*':
95: c = *pattern;
96: /* Collapse multiple stars. */
97: while (c == '*')
98: c = *++pattern;
99:
100: if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
101: (string == stringstart ||
102: (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
103: return FNM_NOMATCH;
104:
105: /* Optimize for pattern with * at end or before /. */
106: if (c == EOS) {
107: if (ISSET(flags, FNM_PATHNAME))
108: return (ISSET(flags, FNM_LEADING_DIR) ||
109: strchr(string, '/') == NULL ?
110: 0 : FNM_NOMATCH);
111: else
112: return 0;
113: } else if (c == '/' && ISSET(flags, FNM_PATHNAME)) {
114: if ((string = strchr(string, '/')) == NULL)
115: return FNM_NOMATCH;
116: break;
117: }
118:
119: /* General case, use recursion. */
120: while ((test = *string) != EOS) {
121: if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
122: return 0;
123: if (test == '/' && ISSET(flags, FNM_PATHNAME))
124: break;
125: ++string;
126: }
127: return FNM_NOMATCH;
128: case '[':
129: if (*string == EOS)
130: return FNM_NOMATCH;
131: if (*string == '/' && ISSET(flags, FNM_PATHNAME))
132: return FNM_NOMATCH;
133: if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
134: (string == stringstart ||
135: (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
136: return FNM_NOMATCH;
137:
138: switch (rangematch(pattern, *string, flags, &newp)) {
139: case RANGE_ERROR:
140: /* not a good range, treat as normal text */
141: goto normal;
142: case RANGE_MATCH:
143: pattern = newp;
144: break;
145: case RANGE_NOMATCH:
146: return FNM_NOMATCH;
147: }
148: ++string;
149: break;
150: case '\\':
151: if (!ISSET(flags, FNM_NOESCAPE)) {
152: if ((c = *pattern++) == EOS) {
153: c = '\\';
154: --pattern;
155: }
156: }
157: /* FALLTHROUGH */
158: default:
159: normal:
160: if (c != *string && !(ISSET(flags, FNM_CASEFOLD) &&
161: (tolower((unsigned char)c) ==
162: tolower((unsigned char)*string))))
163: return FNM_NOMATCH;
164: ++string;
165: break;
166: }
167: /* NOTREACHED */
168: }
169:
170: static int
171: rangematch(const char *pattern, int test, int flags, char **newp)
172: {
173: int negate, ok, rv;
174: char c, c2;
175:
176: /*
177: * A bracket expression starting with an unquoted circumflex
178: * character produces unspecified results (IEEE 1003.2-1992,
179: * 3.13.2). This implementation treats it like '!', for
180: * consistency with the regular expression syntax.
181: * J.T. Conklin (conklin@ngai.kaleida.com)
182: */
183: if ((negate = (*pattern == '!' || *pattern == '^')))
184: ++pattern;
185:
186: if (ISSET(flags, FNM_CASEFOLD))
187: test = tolower(test);
188:
189: /*
190: * A right bracket shall lose its special meaning and represent
191: * itself in a bracket expression if it occurs first in the list.
192: * -- POSIX.2 2.8.3.2
193: */
194: ok = 0;
195: c = *pattern++;
196: do {
197: if (c == '[' && *pattern == ':') {
198: do {
199: rv = classmatch(pattern + 1, test,
200: (flags & FNM_CASEFOLD), &pattern);
201: if (rv == RANGE_MATCH)
202: ok = 1;
203: c = *pattern++;
204: } while (rv != RANGE_ERROR && c == '[' && *pattern == ':');
205: if (c == ']')
206: break;
207: }
208: if (c == '\\' && !ISSET(flags, FNM_NOESCAPE))
209: c = *pattern++;
210: if (c == EOS)
211: return RANGE_ERROR;
212: if (c == '/' && ISSET(flags, FNM_PATHNAME))
213: return RANGE_NOMATCH;
214: if (ISSET(flags, FNM_CASEFOLD))
215: c = tolower((unsigned char)c);
216: if (*pattern == '-'
217: && (c2 = *(pattern+1)) != EOS && c2 != ']') {
218: pattern += 2;
219: if (c2 == '\\' && !ISSET(flags, FNM_NOESCAPE))
220: c2 = *pattern++;
221: if (c2 == EOS)
222: return RANGE_ERROR;
223: if (ISSET(flags, FNM_CASEFOLD))
224: c2 = tolower((unsigned char)c2);
225: if (c <= test && test <= c2)
226: ok = 1;
227: } else if (c == test)
228: ok = 1;
229: } while ((c = *pattern++) != ']');
230:
231: *newp = (char *)pattern;
232: return ok == negate ? RANGE_NOMATCH : RANGE_MATCH;
233: }
234:
235: static int
236: classmatch(const char *pattern, int test, int foldcase, const char **ep)
237: {
238: struct cclass *cc;
239: const char *colon;
240: size_t len;
241: int rval = RANGE_NOMATCH;
242:
243: if ((colon = strchr(pattern, ':')) == NULL || colon[1] != ']') {
244: *ep = pattern - 2;
245: return RANGE_ERROR;
246: }
247: *ep = colon + 2;
248: len = (size_t)(colon - pattern);
249:
250: if (foldcase && strncmp(pattern, "upper:]", 7) == 0)
251: pattern = "lower:]";
252: for (cc = cclasses; cc->name != NULL; cc++) {
253: if (!strncmp(pattern, cc->name, len) && cc->name[len] == '\0') {
254: if (cc->isctype(test))
255: rval = RANGE_MATCH;
256: break;
257: }
258: }
259: if (cc->name == NULL) {
260: /* invalid character class, return EOS */
261: *ep = colon + strlen(colon);
262: rval = RANGE_ERROR;
263: }
264: return rval;
265: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>