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