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