1156230Smux/*
2156230Smux * Copyright (c) 1989, 1993, 1994
3156230Smux *	The Regents of the University of California.  All rights reserved.
4156230Smux *
5156230Smux * This code is derived from software contributed to Berkeley by
6156230Smux * Guido van Rossum.
7156230Smux *
8156230Smux * Redistribution and use in source and binary forms, with or without
9156230Smux * modification, are permitted provided that the following conditions
10156230Smux * are met:
11156230Smux * 1. Redistributions of source code must retain the above copyright
12156230Smux *    notice, this list of conditions and the following disclaimer.
13156230Smux * 2. Redistributions in binary form must reproduce the above copyright
14156230Smux *    notice, this list of conditions and the following disclaimer in the
15156230Smux *    documentation and/or other materials provided with the distribution.
16156230Smux * 4. Neither the name of the University nor the names of its contributors
17156230Smux *    may be used to endorse or promote products derived from this software
18156230Smux *    without specific prior written permission.
19156230Smux *
20156230Smux * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21156230Smux * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22156230Smux * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23156230Smux * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24156230Smux * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25156230Smux * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26156230Smux * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27156230Smux * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28156230Smux * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29156230Smux * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30156230Smux * SUCH DAMAGE.
31156230Smux *
32216370Sjoel * $FreeBSD$
33216370Sjoel *
34156230Smux * From FreeBSD fnmatch.c 1.11
35156230Smux * $Id: fnmatch.c,v 1.3 1997/08/19 02:34:30 jdp Exp $
36156230Smux */
37156230Smux
38156230Smux#if defined(LIBC_SCCS) && !defined(lint)
39156230Smuxstatic char sccsid[] = "@(#)fnmatch.c	8.2 (Berkeley) 4/16/94";
40156230Smux#endif /* LIBC_SCCS and not lint */
41156230Smux
42156230Smux/*
43156230Smux * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
44156230Smux * Compares a filename or pathname to a pattern.
45156230Smux */
46156230Smux
47156230Smux#include <ctype.h>
48156230Smux#include <string.h>
49156230Smux#include <stdio.h>
50156230Smux
51156230Smux#include "fnmatch.h"
52156230Smux
53156230Smux#define	EOS	'\0'
54156230Smux
55156230Smuxstatic const char *rangematch(const char *, char, int);
56156230Smux
57156230Smuxint
58156230Smuxfnmatch(const char *pattern, const char *string, int flags)
59156230Smux{
60156230Smux	const char *stringstart;
61156230Smux	char c, test;
62156230Smux
63156230Smux	for (stringstart = string;;)
64156230Smux		switch (c = *pattern++) {
65156230Smux		case EOS:
66156230Smux			if ((flags & FNM_LEADING_DIR) && *string == '/')
67156230Smux				return (0);
68156230Smux			return (*string == EOS ? 0 : FNM_NOMATCH);
69156230Smux		case '?':
70156230Smux			if (*string == EOS)
71156230Smux				return (FNM_NOMATCH);
72156230Smux			if (*string == '/' && (flags & FNM_PATHNAME))
73156230Smux				return (FNM_NOMATCH);
74156230Smux			if (*string == '.' && (flags & FNM_PERIOD) &&
75156230Smux			    (string == stringstart ||
76156230Smux			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
77156230Smux				return (FNM_NOMATCH);
78156230Smux			++string;
79156230Smux			break;
80156230Smux		case '*':
81156230Smux			c = *pattern;
82156230Smux			/* Collapse multiple stars. */
83156230Smux			while (c == '*')
84156230Smux				c = *++pattern;
85156230Smux
86156230Smux			if (*string == '.' && (flags & FNM_PERIOD) &&
87156230Smux			    (string == stringstart ||
88156230Smux			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
89156230Smux				return (FNM_NOMATCH);
90156230Smux
91156230Smux			/* Optimize for pattern with * at end or before /. */
92156230Smux			if (c == EOS)
93156230Smux				if (flags & FNM_PATHNAME)
94156230Smux					return ((flags & FNM_LEADING_DIR) ||
95156230Smux					    strchr(string, '/') == NULL ?
96156230Smux					    0 : FNM_NOMATCH);
97156230Smux				else
98156230Smux					return (0);
99156230Smux			else if (c == '/' && flags & FNM_PATHNAME) {
100156230Smux				if ((string = strchr(string, '/')) == NULL)
101156230Smux					return (FNM_NOMATCH);
102156230Smux				break;
103156230Smux			}
104156230Smux
105156230Smux			/* General case, use recursion. */
106156230Smux			while ((test = *string) != EOS) {
107156230Smux				if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
108156230Smux					return (0);
109156230Smux				if (test == '/' && flags & FNM_PATHNAME)
110156230Smux					break;
111156230Smux				++string;
112156230Smux			}
113156230Smux			return (FNM_NOMATCH);
114156230Smux		case '[':
115156230Smux			if (*string == EOS)
116156230Smux				return (FNM_NOMATCH);
117156230Smux			if (*string == '/' && flags & FNM_PATHNAME)
118156230Smux				return (FNM_NOMATCH);
119156230Smux			if ((pattern =
120156230Smux			    rangematch(pattern, *string, flags)) == NULL)
121156230Smux				return (FNM_NOMATCH);
122156230Smux			++string;
123156230Smux			break;
124156230Smux		case '\\':
125156230Smux			if (!(flags & FNM_NOESCAPE)) {
126156230Smux				if ((c = *pattern++) == EOS) {
127156230Smux					c = '\\';
128156230Smux					--pattern;
129156230Smux				}
130156230Smux			}
131156230Smux			/* FALLTHROUGH */
132156230Smux		default:
133156230Smux			if (c == *string)
134156230Smux				;
135156230Smux			else if ((flags & FNM_CASEFOLD) &&
136156230Smux				 (tolower((unsigned char)c) ==
137156230Smux				  tolower((unsigned char)*string)))
138156230Smux				;
139156230Smux			else if ((flags & FNM_PREFIX_DIRS) && *string == EOS &&
140156230Smux			     ((c == '/' && string != stringstart) ||
141156230Smux			     (string == stringstart+1 && *stringstart == '/')))
142156230Smux				return (0);
143156230Smux			else
144156230Smux				return (FNM_NOMATCH);
145156230Smux			string++;
146156230Smux			break;
147156230Smux		}
148156230Smux	/* NOTREACHED */
149156230Smux}
150156230Smux
151156230Smuxstatic const char *
152156230Smuxrangematch(const char *pattern, char test, int flags)
153156230Smux{
154156230Smux	int negate, ok;
155156230Smux	char c, c2;
156156230Smux
157156230Smux	/*
158156230Smux	 * A bracket expression starting with an unquoted circumflex
159156230Smux	 * character produces unspecified results (IEEE 1003.2-1992,
160156230Smux	 * 3.13.2).  This implementation treats it like '!', for
161156230Smux	 * consistency with the regular expression syntax.
162156230Smux	 * J.T. Conklin (conklin@ngai.kaleida.com)
163156230Smux	 */
164156230Smux	if ( (negate = (*pattern == '!' || *pattern == '^')) )
165156230Smux		++pattern;
166156230Smux
167156230Smux	if (flags & FNM_CASEFOLD)
168156230Smux		test = tolower((unsigned char)test);
169156230Smux
170156230Smux	for (ok = 0; (c = *pattern++) != ']';) {
171156230Smux		if (c == '\\' && !(flags & FNM_NOESCAPE))
172156230Smux			c = *pattern++;
173156230Smux		if (c == EOS)
174156230Smux			return (NULL);
175156230Smux
176156230Smux		if (flags & FNM_CASEFOLD)
177156230Smux			c = tolower((unsigned char)c);
178156230Smux
179156230Smux		if (*pattern == '-'
180156230Smux		    && (c2 = *(pattern+1)) != EOS && c2 != ']') {
181156230Smux			pattern += 2;
182156230Smux			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
183156230Smux				c2 = *pattern++;
184156230Smux			if (c2 == EOS)
185156230Smux				return (NULL);
186156230Smux
187156230Smux			if (flags & FNM_CASEFOLD)
188156230Smux				c2 = tolower((unsigned char)c2);
189156230Smux
190156230Smux			if ((unsigned char)c <= (unsigned char)test &&
191156230Smux			    (unsigned char)test <= (unsigned char)c2)
192156230Smux				ok = 1;
193156230Smux		} else if (c == test)
194156230Smux			ok = 1;
195156230Smux	}
196156230Smux	return (ok == negate ? NULL : pattern);
197156230Smux}
198