fnmatch.c revision 1573
1199080Sume/* 2199080Sume * Copyright (c) 1989, 1993, 1994 3199082Sume * The Regents of the University of California. All rights reserved. 4199080Sume * 5199080Sume * This code is derived from software contributed to Berkeley by 6199080Sume * Guido van Rossum. 7199080Sume * 8199080Sume * Redistribution and use in source and binary forms, with or without 9199080Sume * modification, are permitted provided that the following conditions 10199080Sume * are met: 11199080Sume * 1. Redistributions of source code must retain the above copyright 12199080Sume * notice, this list of conditions and the following disclaimer. 13199080Sume * 2. Redistributions in binary form must reproduce the above copyright 14199080Sume * notice, this list of conditions and the following disclaimer in the 15199080Sume * documentation and/or other materials provided with the distribution. 16199080Sume * 3. All advertising materials mentioning features or use of this software 17199080Sume * must display the following acknowledgement: 18199080Sume * This product includes software developed by the University of 19199080Sume * California, Berkeley and its contributors. 20199080Sume * 4. Neither the name of the University nor the names of its contributors 21199080Sume * may be used to endorse or promote products derived from this software 22199080Sume * without specific prior written permission. 23199080Sume * 24199080Sume * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25199080Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26199080Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27199080Sume * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28199080Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29199080Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30199080Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31199080Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32199080Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33199080Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34199080Sume * SUCH DAMAGE. 35199080Sume */ 36199080Sume 37199080Sume#if defined(LIBC_SCCS) && !defined(lint) 38199080Sumestatic char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; 39199080Sume#endif /* LIBC_SCCS and not lint */ 40199080Sume 41199080Sume/* 42199080Sume * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. 43199080Sume * Compares a filename or pathname to a pattern. 44199080Sume */ 45199080Sume 46199080Sume#include <fnmatch.h> 47199080Sume#include <string.h> 48199080Sume 49199080Sume#define EOS '\0' 50199080Sume 51199080Sumestatic const char *rangematch __P((const char *, int, int)); 52199080Sume 53199080Sumeint 54199080Sumefnmatch(pattern, string, flags) 55199080Sume const char *pattern, *string; 56199080Sume int flags; 57199080Sume{ 58199080Sume const char *stringstart; 59199080Sume char c, test; 60199080Sume 61199080Sume for (stringstart = string;;) 62199080Sume switch (c = *pattern++) { 63199080Sume case EOS: 64199080Sume return (*string == EOS ? 0 : FNM_NOMATCH); 65199080Sume case '?': 66199080Sume if (*string == EOS) 67199080Sume return (FNM_NOMATCH); 68199080Sume if (*string == '/' && (flags & FNM_PATHNAME)) 69199080Sume return (FNM_NOMATCH); 70199080Sume if (*string == '.' && (flags & FNM_PERIOD) && 71199080Sume (string == stringstart || 72199080Sume ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) 73199080Sume return (FNM_NOMATCH); 74199080Sume ++string; 75199080Sume break; 76199080Sume case '*': 77199080Sume c = *pattern; 78199080Sume /* Collapse multiple stars. */ 79199080Sume while (c == '*') 80199080Sume c = *++pattern; 81199080Sume 82199080Sume if (*string == '.' && (flags & FNM_PERIOD) && 83199080Sume (string == stringstart || 84199080Sume ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) 85199080Sume return (FNM_NOMATCH); 86199080Sume 87199080Sume /* Optimize for pattern with * at end or before /. */ 88199080Sume if (c == EOS) 89199080Sume if (flags & FNM_PATHNAME) 90199080Sume return (strchr(string, '/') == NULL ? 91199080Sume 0 : FNM_NOMATCH); 92199080Sume else 93199080Sume return (0); 94199080Sume else if (c == '/' && flags & FNM_PATHNAME) { 95199080Sume if ((string = strchr(string, '/')) == NULL) 96199080Sume return (FNM_NOMATCH); 97199080Sume break; 98199080Sume } 99199080Sume 100199080Sume /* General case, use recursion. */ 101199080Sume while ((test = *string) != EOS) { 102199080Sume if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) 103199080Sume return (0); 104199080Sume if (test == '/' && flags & FNM_PATHNAME) 105199080Sume break; 106199080Sume ++string; 107199080Sume } 108199080Sume return (FNM_NOMATCH); 109199080Sume case '[': 110199080Sume if (*string == EOS) 111199080Sume return (FNM_NOMATCH); 112199080Sume if (*string == '/' && flags & FNM_PATHNAME) 113199080Sume return (FNM_NOMATCH); 114199080Sume if ((pattern = 115199080Sume rangematch(pattern, *string, flags)) == NULL) 116199080Sume return (FNM_NOMATCH); 117199080Sume ++string; 118199080Sume break; 119199080Sume case '\\': 120199080Sume if (!(flags & FNM_NOESCAPE)) { 121199080Sume if ((c = *pattern++) == EOS) { 122199080Sume c = '\\'; 123199080Sume --pattern; 124199080Sume } 125199080Sume } 126199080Sume /* FALLTHROUGH */ 127199080Sume default: 128199080Sume if (c != *string++) 129199080Sume return (FNM_NOMATCH); 130199080Sume break; 131199080Sume } 132199080Sume /* NOTREACHED */ 133199080Sume} 134199080Sume 135199080Sumestatic const char * 136199080Sumerangematch(pattern, test, flags) 137199080Sume const char *pattern; 138199080Sume int test, flags; 139199080Sume{ 140199080Sume int negate, ok; 141199080Sume char c, c2; 142199080Sume 143199080Sume /* 144199080Sume * A bracket expression starting with an unquoted circumflex 145199080Sume * character produces unspecified results (IEEE 1003.2-1992, 146199080Sume * 3.13.2). This implementation treats it like '!', for 147199080Sume * consistency with the regular expression syntax. 148199080Sume * J.T. Conklin (conklin@ngai.kaleida.com) 149199080Sume */ 150199080Sume if (negate = (*pattern == '!' || *pattern == '^')) 151199080Sume ++pattern; 152199080Sume 153199080Sume for (ok = 0; (c = *pattern++) != ']';) { 154199080Sume if (c == '\\' && !(flags & FNM_NOESCAPE)) 155199080Sume c = *pattern++; 156199080Sume if (c == EOS) 157199080Sume return (NULL); 158199080Sume if (*pattern == '-' 159199080Sume && (c2 = *(pattern+1)) != EOS && c2 != ']') { 160199080Sume pattern += 2; 161199080Sume if (c2 == '\\' && !(flags & FNM_NOESCAPE)) 162199080Sume c2 = *pattern++; 163199080Sume if (c2 == EOS) 164199080Sume return (NULL); 165199080Sume if (c <= test && test <= c2) 166199080Sume ok = 1; 167199080Sume } else if (c == test) 168199080Sume ok = 1; 169199080Sume } 170199080Sume return (ok == negate ? NULL : pattern); 171199080Sume} 172199080Sume