fnmatch.c revision 26484
11573Srgrimes/*
21573Srgrimes * Copyright (c) 1989, 1993, 1994
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Guido van Rossum.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
161573Srgrimes * 3. All advertising materials mentioning features or use of this software
171573Srgrimes *    must display the following acknowledgement:
181573Srgrimes *	This product includes software developed by the University of
191573Srgrimes *	California, Berkeley and its contributors.
201573Srgrimes * 4. Neither the name of the University nor the names of its contributors
211573Srgrimes *    may be used to endorse or promote products derived from this software
221573Srgrimes *    without specific prior written permission.
231573Srgrimes *
241573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341573Srgrimes * SUCH DAMAGE.
351573Srgrimes */
361573Srgrimes
371573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
381573Srgrimesstatic char sccsid[] = "@(#)fnmatch.c	8.2 (Berkeley) 4/16/94";
391573Srgrimes#endif /* LIBC_SCCS and not lint */
401573Srgrimes
411573Srgrimes/*
421573Srgrimes * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
431573Srgrimes * Compares a filename or pathname to a pattern.
441573Srgrimes */
451573Srgrimes
4619059Swosch#include <ctype.h>
471573Srgrimes#include <fnmatch.h>
481573Srgrimes#include <string.h>
4919059Swosch#include <stdio.h>
501573Srgrimes
5119276Sache#include "collate.h"
5219276Sache
531573Srgrimes#define	EOS	'\0'
541573Srgrimes
5526484Sache#define RANGE_MATCH     1
5626484Sache#define RANGE_NOMATCH   0
5726484Sache#define RANGE_ERROR     (-1)
581573Srgrimes
5926484Sachestatic int rangematch __P((const char *, char, int, char **));
6026484Sache
611573Srgrimesint
621573Srgrimesfnmatch(pattern, string, flags)
631573Srgrimes	const char *pattern, *string;
641573Srgrimes	int flags;
651573Srgrimes{
661573Srgrimes	const char *stringstart;
6726484Sache	char *newp;
681573Srgrimes	char c, test;
691573Srgrimes
701573Srgrimes	for (stringstart = string;;)
711573Srgrimes		switch (c = *pattern++) {
721573Srgrimes		case EOS:
7319132Sache			if ((flags & FNM_LEADING_DIR) && *string == '/')
7419132Sache				return (0);
751573Srgrimes			return (*string == EOS ? 0 : FNM_NOMATCH);
761573Srgrimes		case '?':
771573Srgrimes			if (*string == EOS)
781573Srgrimes				return (FNM_NOMATCH);
791573Srgrimes			if (*string == '/' && (flags & FNM_PATHNAME))
801573Srgrimes				return (FNM_NOMATCH);
811573Srgrimes			if (*string == '.' && (flags & FNM_PERIOD) &&
821573Srgrimes			    (string == stringstart ||
831573Srgrimes			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
841573Srgrimes				return (FNM_NOMATCH);
851573Srgrimes			++string;
861573Srgrimes			break;
871573Srgrimes		case '*':
881573Srgrimes			c = *pattern;
891573Srgrimes			/* Collapse multiple stars. */
901573Srgrimes			while (c == '*')
911573Srgrimes				c = *++pattern;
921573Srgrimes
931573Srgrimes			if (*string == '.' && (flags & FNM_PERIOD) &&
941573Srgrimes			    (string == stringstart ||
951573Srgrimes			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
961573Srgrimes				return (FNM_NOMATCH);
971573Srgrimes
981573Srgrimes			/* Optimize for pattern with * at end or before /. */
991573Srgrimes			if (c == EOS)
1001573Srgrimes				if (flags & FNM_PATHNAME)
10125269Sjdp					return ((flags & FNM_LEADING_DIR) ||
10225269Sjdp					    strchr(string, '/') == NULL ?
1031573Srgrimes					    0 : FNM_NOMATCH);
1041573Srgrimes				else
1051573Srgrimes					return (0);
1061573Srgrimes			else if (c == '/' && flags & FNM_PATHNAME) {
1071573Srgrimes				if ((string = strchr(string, '/')) == NULL)
1081573Srgrimes					return (FNM_NOMATCH);
1091573Srgrimes				break;
1101573Srgrimes			}
1111573Srgrimes
1121573Srgrimes			/* General case, use recursion. */
1131573Srgrimes			while ((test = *string) != EOS) {
1141573Srgrimes				if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
1151573Srgrimes					return (0);
1161573Srgrimes				if (test == '/' && flags & FNM_PATHNAME)
1171573Srgrimes					break;
1181573Srgrimes				++string;
1191573Srgrimes			}
1201573Srgrimes			return (FNM_NOMATCH);
1211573Srgrimes		case '[':
1221573Srgrimes			if (*string == EOS)
1231573Srgrimes				return (FNM_NOMATCH);
1241573Srgrimes			if (*string == '/' && flags & FNM_PATHNAME)
1251573Srgrimes				return (FNM_NOMATCH);
12626484Sache			switch (rangematch(pattern, *string, flags, &newp)) {
12726484Sache			case RANGE_ERROR:
12826484Sache				goto norm;
12926484Sache			case RANGE_MATCH:
13026484Sache				pattern = newp;
13126484Sache				break;
13226484Sache			case RANGE_NOMATCH:
1331573Srgrimes				return (FNM_NOMATCH);
13426484Sache			}
1351573Srgrimes			++string;
1361573Srgrimes			break;
1371573Srgrimes		case '\\':
1381573Srgrimes			if (!(flags & FNM_NOESCAPE)) {
1391573Srgrimes				if ((c = *pattern++) == EOS) {
1401573Srgrimes					c = '\\';
1411573Srgrimes					--pattern;
1421573Srgrimes				}
1431573Srgrimes			}
1441573Srgrimes			/* FALLTHROUGH */
1451573Srgrimes		default:
14626484Sache		norm:
14719059Swosch			if (c == *string)
14819059Swosch				;
14919132Sache			else if ((flags & FNM_CASEFOLD) &&
15019132Sache				 (tolower((unsigned char)c) ==
15119132Sache				  tolower((unsigned char)*string)))
15219059Swosch				;
15319059Swosch			else
1541573Srgrimes				return (FNM_NOMATCH);
15519059Swosch			string++;
1561573Srgrimes			break;
1571573Srgrimes		}
1581573Srgrimes	/* NOTREACHED */
1591573Srgrimes}
1601573Srgrimes
16126484Sachestatic int
16226484Sacherangematch(pattern, test, flags, newp)
1631573Srgrimes	const char *pattern;
16419132Sache	char test;
16519132Sache	int flags;
16626484Sache	char **newp;
1671573Srgrimes{
16826484Sache	int negate, ok, first;
1691573Srgrimes	char c, c2;
1701573Srgrimes
17126484Sache	first = 1;
17226484Sache
1731573Srgrimes	/*
1741573Srgrimes	 * A bracket expression starting with an unquoted circumflex
1751573Srgrimes	 * character produces unspecified results (IEEE 1003.2-1992,
1761573Srgrimes	 * 3.13.2).  This implementation treats it like '!', for
1771573Srgrimes	 * consistency with the regular expression syntax.
1781573Srgrimes	 * J.T. Conklin (conklin@ngai.kaleida.com)
1791573Srgrimes	 */
18026484Sache	if ( (negate = (*pattern == '!' || *pattern == '^')) ) {
18126484Sache		first = 0;
1821573Srgrimes		++pattern;
18326484Sache	}
1848870Srgrimes
18519132Sache	if (flags & FNM_CASEFOLD)
18619132Sache		test = tolower((unsigned char)test);
18719059Swosch
18826484Sache	/*
18926484Sache	 * A right bracket shall lose its special meaning and represent
19026484Sache	 * itself in a bracket expression if it occurs first in the list.
19126484Sache	 * -- POSIX.2 2.8.3.2
19226484Sache	 */
19326484Sache	for (ok = 0, c = *pattern++; c != ']' || first; c = *pattern++) {
19426484Sache		first = 0;
1951573Srgrimes		if (c == '\\' && !(flags & FNM_NOESCAPE))
1961573Srgrimes			c = *pattern++;
1971573Srgrimes		if (c == EOS)
19826484Sache			return (RANGE_ERROR);
19919059Swosch
20019132Sache		if (flags & FNM_CASEFOLD)
20119132Sache			c = tolower((unsigned char)c);
20219059Swosch
2038870Srgrimes		if (*pattern == '-'
2041573Srgrimes		    && (c2 = *(pattern+1)) != EOS && c2 != ']') {
2051573Srgrimes			pattern += 2;
2061573Srgrimes			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
2071573Srgrimes				c2 = *pattern++;
2081573Srgrimes			if (c2 == EOS)
20926484Sache				return (RANGE_ERROR);
21019059Swosch
21119132Sache			if (flags & FNM_CASEFOLD)
21219132Sache				c2 = tolower((unsigned char)c2);
21319059Swosch
21424632Sache			if (__collate_load_error ?
21524632Sache			    c <= test && test <= c2 :
21624632Sache			       __collate_range_cmp(c, test) <= 0
21724632Sache			    && __collate_range_cmp(test, c2) <= 0
21817533Sache			   )
2191573Srgrimes				ok = 1;
2201573Srgrimes		} else if (c == test)
2211573Srgrimes			ok = 1;
2221573Srgrimes	}
22326484Sache	*newp = (char *)pattern;
22426484Sache	return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
2251573Srgrimes}
226