155682Smarkm/*	$NetBSD: fnmatch.c,v 1.11 1995/02/27 03:43:06 cgd Exp $	*/
255682Smarkm
355682Smarkm/*
455682Smarkm * Copyright (c) 1989, 1993, 1994
555682Smarkm *	The Regents of the University of California.  All rights reserved.
655682Smarkm *
755682Smarkm * This code is derived from software contributed to Berkeley by
855682Smarkm * Guido van Rossum.
955682Smarkm *
1055682Smarkm * Redistribution and use in source and binary forms, with or without
1155682Smarkm * modification, are permitted provided that the following conditions
1255682Smarkm * are met:
1355682Smarkm * 1. Redistributions of source code must retain the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer.
1555682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1655682Smarkm *    notice, this list of conditions and the following disclaimer in the
1755682Smarkm *    documentation and/or other materials provided with the distribution.
18178825Sdfr * 3. Neither the name of the University nor the names of its contributors
1955682Smarkm *    may be used to endorse or promote products derived from this software
2055682Smarkm *    without specific prior written permission.
2155682Smarkm *
2255682Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2355682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2455682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2555682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2655682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2755682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2855682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2955682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3055682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3155682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3255682Smarkm * SUCH DAMAGE.
3355682Smarkm */
3455682Smarkm
3555682Smarkm#if defined(LIBC_SCCS) && !defined(lint)
3655682Smarkm#if 0
3755682Smarkmstatic char sccsid[] = "@(#)fnmatch.c	8.2 (Berkeley) 4/16/94";
3855682Smarkm#else
3955682Smarkmstatic char rcsid[] = "$NetBSD: fnmatch.c,v 1.11 1995/02/27 03:43:06 cgd Exp $";
4055682Smarkm#endif
4155682Smarkm#endif /* LIBC_SCCS and not lint */
4255682Smarkm
4355682Smarkm/*
4455682Smarkm * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
4555682Smarkm * Compares a filename or pathname to a pattern.
4655682Smarkm */
4755682Smarkm
48233294Sstas#ifdef HAVE_CONFIG_H
49233294Sstas#include <config.h>
50233294Sstas#endif
51233294Sstas
52233294Sstas#include <roken.h>
53233294Sstas
5455682Smarkm#include <fnmatch.h>
5555682Smarkm#include <string.h>
5655682Smarkm
5755682Smarkm#define	EOS	'\0'
5855682Smarkm
5955682Smarkmstatic const char *rangematch (const char *, int, int);
6055682Smarkm
61233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
62178825Sdfrrk_fnmatch(const char *pattern, const char *string, int flags)
6355682Smarkm{
6455682Smarkm	const char *stringstart;
6555682Smarkm	char c, test;
6655682Smarkm
6755682Smarkm	for (stringstart = string;;)
6855682Smarkm		switch (c = *pattern++) {
6955682Smarkm		case EOS:
7055682Smarkm			return (*string == EOS ? 0 : FNM_NOMATCH);
7155682Smarkm		case '?':
7255682Smarkm			if (*string == EOS)
7355682Smarkm				return (FNM_NOMATCH);
7455682Smarkm			if (*string == '/' && (flags & FNM_PATHNAME))
7555682Smarkm				return (FNM_NOMATCH);
7655682Smarkm			if (*string == '.' && (flags & FNM_PERIOD) &&
7755682Smarkm			    (string == stringstart ||
7855682Smarkm			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
7955682Smarkm				return (FNM_NOMATCH);
8055682Smarkm			++string;
8155682Smarkm			break;
8255682Smarkm		case '*':
8355682Smarkm			c = *pattern;
8455682Smarkm			/* Collapse multiple stars. */
8555682Smarkm			while (c == '*')
8655682Smarkm				c = *++pattern;
8755682Smarkm
8855682Smarkm			if (*string == '.' && (flags & FNM_PERIOD) &&
8955682Smarkm			    (string == stringstart ||
9055682Smarkm			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
9155682Smarkm				return (FNM_NOMATCH);
9255682Smarkm
9355682Smarkm			/* Optimize for pattern with * at end or before /. */
9455682Smarkm			if (c == EOS)
9555682Smarkm				if (flags & FNM_PATHNAME)
9655682Smarkm					return (strchr(string, '/') == NULL ?
9755682Smarkm					    0 : FNM_NOMATCH);
9855682Smarkm				else
9955682Smarkm					return (0);
10055682Smarkm			else if (c == '/' && flags & FNM_PATHNAME) {
10155682Smarkm				if ((string = strchr(string, '/')) == NULL)
10255682Smarkm					return (FNM_NOMATCH);
10355682Smarkm				break;
10455682Smarkm			}
10555682Smarkm
10655682Smarkm			/* General case, use recursion. */
10755682Smarkm			while ((test = *string) != EOS) {
108178825Sdfr				if (!rk_fnmatch(pattern, string, flags & ~FNM_PERIOD))
10955682Smarkm					return (0);
11055682Smarkm				if (test == '/' && flags & FNM_PATHNAME)
11155682Smarkm					break;
11255682Smarkm				++string;
11355682Smarkm			}
11455682Smarkm			return (FNM_NOMATCH);
11555682Smarkm		case '[':
11655682Smarkm			if (*string == EOS)
11755682Smarkm				return (FNM_NOMATCH);
11855682Smarkm			if (*string == '/' && flags & FNM_PATHNAME)
11955682Smarkm				return (FNM_NOMATCH);
12055682Smarkm			if ((pattern =
12155682Smarkm			    rangematch(pattern, *string, flags)) == NULL)
12255682Smarkm				return (FNM_NOMATCH);
12355682Smarkm			++string;
12455682Smarkm			break;
12555682Smarkm		case '\\':
12655682Smarkm			if (!(flags & FNM_NOESCAPE)) {
12755682Smarkm				if ((c = *pattern++) == EOS) {
12855682Smarkm					c = '\\';
12955682Smarkm					--pattern;
13055682Smarkm				}
13155682Smarkm			}
13255682Smarkm			/* FALLTHROUGH */
13355682Smarkm		default:
13455682Smarkm			if (c != *string++)
13555682Smarkm				return (FNM_NOMATCH);
13655682Smarkm			break;
13755682Smarkm		}
13855682Smarkm	/* NOTREACHED */
13955682Smarkm}
14055682Smarkm
14155682Smarkmstatic const char *
14255682Smarkmrangematch(const char *pattern, int test, int flags)
14355682Smarkm{
14455682Smarkm	int negate, ok;
14555682Smarkm	char c, c2;
14655682Smarkm
14755682Smarkm	/*
14855682Smarkm	 * A bracket expression starting with an unquoted circumflex
14955682Smarkm	 * character produces unspecified results (IEEE 1003.2-1992,
15055682Smarkm	 * 3.13.2).  This implementation treats it like '!', for
15155682Smarkm	 * consistency with the regular expression syntax.
15255682Smarkm	 * J.T. Conklin (conklin@ngai.kaleida.com)
15355682Smarkm	 */
15455682Smarkm	if (negate = (*pattern == '!' || *pattern == '^'))
15555682Smarkm		++pattern;
156233294Sstas
15755682Smarkm	for (ok = 0; (c = *pattern++) != ']';) {
15855682Smarkm		if (c == '\\' && !(flags & FNM_NOESCAPE))
15955682Smarkm			c = *pattern++;
16055682Smarkm		if (c == EOS)
16155682Smarkm			return (NULL);
162233294Sstas		if (*pattern == '-'
16355682Smarkm		    && (c2 = *(pattern+1)) != EOS && c2 != ']') {
16455682Smarkm			pattern += 2;
16555682Smarkm			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
16655682Smarkm				c2 = *pattern++;
16755682Smarkm			if (c2 == EOS)
16855682Smarkm				return (NULL);
16955682Smarkm			if (c <= test && test <= c2)
17055682Smarkm				ok = 1;
17155682Smarkm		} else if (c == test)
17255682Smarkm			ok = 1;
17355682Smarkm	}
17455682Smarkm	return (ok == negate ? NULL : pattern);
17555682Smarkm}
176