fnmatch.c revision 17552
123599Smarkm/*
251694Sroger * Copyright (c) 1989, 1993, 1994
351694Sroger *	The Regents of the University of California.  All rights reserved.
448781Sroger *
548781Sroger * This code is derived from software contributed to Berkeley by
623599Smarkm * Guido van Rossum.
723599Smarkm *
823599Smarkm * Redistribution and use in source and binary forms, with or without
923599Smarkm * modification, are permitted provided that the following conditions
1023599Smarkm * are met:
1123599Smarkm * 1. Redistributions of source code must retain the above copyright
1223599Smarkm *    notice, this list of conditions and the following disclaimer.
1323599Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1423599Smarkm *    notice, this list of conditions and the following disclaimer in the
1523599Smarkm *    documentation and/or other materials provided with the distribution.
1623599Smarkm * 3. All advertising materials mentioning features or use of this software
1723599Smarkm *    must display the following acknowledgement:
1823599Smarkm *	This product includes software developed by the University of
1923599Smarkm *	California, Berkeley and its contributors.
2023599Smarkm * 4. Neither the name of the University nor the names of its contributors
2123599Smarkm *    may be used to endorse or promote products derived from this software
2223599Smarkm *    without specific prior written permission.
2323599Smarkm *
2423599Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2523599Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2623599Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2723599Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2823599Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2923599Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3023599Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3123599Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3223599Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3323599Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3439838Ssos * SUCH DAMAGE.
3523599Smarkm */
3651694Sroger
3759014Sroger#if defined(LIBC_SCCS) && !defined(lint)
3859014Srogerstatic char sccsid[] = "@(#)fnmatch.c	8.2 (Berkeley) 4/16/94";
3959014Sroger#endif /* LIBC_SCCS and not lint */
4059014Sroger
4162112Sroger/*
4262112Sroger * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
4362112Sroger * Compares a filename or pathname to a pattern.
4462112Sroger */
4562112Sroger
4651694Sroger#include <fnmatch.h>
4751694Sroger#include <locale.h>
4862112Sroger#include <string.h>
4962112Sroger
5062112Sroger#define	EOS	'\0'
5162112Sroger
5262112Srogerstatic const char *rangematch __P((const char *, int, int));
5362112Sroger
5467306Srogerint
5567306Srogerfnmatch(pattern, string, flags)
5667306Sroger	const char *pattern, *string;
5767306Sroger	int flags;
5862112Sroger{
5962112Sroger	const char *stringstart;
6062112Sroger	char c, test;
6162112Sroger
6262112Sroger	for (stringstart = string;;)
6362112Sroger		switch (c = *pattern++) {
6462112Sroger		case EOS:
6562112Sroger			return (*string == EOS ? 0 : FNM_NOMATCH);
6662112Sroger		case '?':
6762112Sroger			if (*string == EOS)
6862112Sroger				return (FNM_NOMATCH);
6962112Sroger			if (*string == '/' && (flags & FNM_PATHNAME))
7062112Sroger				return (FNM_NOMATCH);
7162112Sroger			if (*string == '.' && (flags & FNM_PERIOD) &&
7262112Sroger			    (string == stringstart ||
7362112Sroger			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
7462112Sroger				return (FNM_NOMATCH);
7562112Sroger			++string;
7662112Sroger			break;
7762112Sroger		case '*':
7862112Sroger			c = *pattern;
7962112Sroger			/* Collapse multiple stars. */
8062112Sroger			while (c == '*')
8123599Smarkm				c = *++pattern;
8223599Smarkm
8323599Smarkm			if (*string == '.' && (flags & FNM_PERIOD) &&
8423599Smarkm			    (string == stringstart ||
8523599Smarkm			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
8647884Sroger				return (FNM_NOMATCH);
8723599Smarkm
8867306Sroger			/* Optimize for pattern with * at end or before /. */
8967306Sroger			if (c == EOS)
9067306Sroger				if (flags & FNM_PATHNAME)
9167306Sroger					return (strchr(string, '/') == NULL ?
9267306Sroger					    0 : FNM_NOMATCH);
9323599Smarkm				else
9467306Sroger					return (0);
9567306Sroger			else if (c == '/' && flags & FNM_PATHNAME) {
9667306Sroger				if ((string = strchr(string, '/')) == NULL)
9767306Sroger					return (FNM_NOMATCH);
9867306Sroger				break;
9967306Sroger			}
10067306Sroger
10167306Sroger			/* General case, use recursion. */
10267306Sroger			while ((test = *string) != EOS) {
10367306Sroger				if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
10467306Sroger					return (0);
10567306Sroger				if (test == '/' && flags & FNM_PATHNAME)
10667306Sroger					break;
10767306Sroger				++string;
10843771Sroger			}
10943771Sroger			return (FNM_NOMATCH);
11047492Sroger		case '[':
11143771Sroger			if (*string == EOS)
11243771Sroger				return (FNM_NOMATCH);
11343771Sroger			if (*string == '/' && flags & FNM_PATHNAME)
11424246Sfsmp				return (FNM_NOMATCH);
11524246Sfsmp			if ((pattern =
11624246Sfsmp			    rangematch(pattern, *string, flags)) == NULL)
11724246Sfsmp				return (FNM_NOMATCH);
11824246Sfsmp			++string;
11924246Sfsmp			break;
12024246Sfsmp		case '\\':
12124246Sfsmp			if (!(flags & FNM_NOESCAPE)) {
12224246Sfsmp				if ((c = *pattern++) == EOS) {
12323599Smarkm					c = '\\';
12424246Sfsmp					--pattern;
12524246Sfsmp				}
12624528Sfsmp			}
12724528Sfsmp			/* FALLTHROUGH */
12824528Sfsmp		default:
12924528Sfsmp			if (c != *string++)
13024528Sfsmp				return (FNM_NOMATCH);
13138707Ssos			break;
13224528Sfsmp		}
13324528Sfsmp	/* NOTREACHED */
13424246Sfsmp}
13524528Sfsmp
13624528Sfsmpstatic const char *
13724528Sfsmprangematch(pattern, test, flags)
13824528Sfsmp	const char *pattern;
13937611Sahasty	int test, flags;
14024528Sfsmp{
14124528Sfsmp	int negate, ok;
14224528Sfsmp	char c, c2;
14324528Sfsmp
14424528Sfsmp	/*
14524528Sfsmp	 * A bracket expression starting with an unquoted circumflex
14624246Sfsmp	 * character produces unspecified results (IEEE 1003.2-1992,
14724246Sfsmp	 * 3.13.2).  This implementation treats it like '!', for
14824246Sfsmp	 * consistency with the regular expression syntax.
14924246Sfsmp	 * J.T. Conklin (conklin@ngai.kaleida.com)
15024246Sfsmp	 */
15124246Sfsmp	if ( (negate = (*pattern == '!' || *pattern == '^')) )
15224246Sfsmp		++pattern;
15324246Sfsmp
15424246Sfsmp	for (ok = 0; (c = *pattern++) != ']';) {
15524246Sfsmp		if (c == '\\' && !(flags & FNM_NOESCAPE))
15624528Sfsmp			c = *pattern++;
15724528Sfsmp		if (c == EOS)
15824528Sfsmp			return (NULL);
15924528Sfsmp		if (*pattern == '-'
16024528Sfsmp		    && (c2 = *(pattern+1)) != EOS && c2 != ']') {
16124528Sfsmp			pattern += 2;
16224528Sfsmp			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
16324528Sfsmp				c2 = *pattern++;
16424246Sfsmp			if (c2 == EOS)
16524246Sfsmp				return (NULL);
16624246Sfsmp			if (   collate_range_cmp(c, test) <= 0
16724246Sfsmp			    && collate_range_cmp(test, c2) <= 0
16824246Sfsmp			   )
16924528Sfsmp				ok = 1;
17024528Sfsmp		} else if (c == test)
17124528Sfsmp			ok = 1;
17224528Sfsmp	}
17324528Sfsmp	return (ok == negate ? NULL : pattern);
17424528Sfsmp}
17524528Sfsmp