1b528cefcSMark Murray /* $NetBSD: fnmatch.c,v 1.11 1995/02/27 03:43:06 cgd Exp $ */ 2b528cefcSMark Murray 3b528cefcSMark Murray /* 4b528cefcSMark Murray * Copyright (c) 1989, 1993, 1994 5b528cefcSMark Murray * The Regents of the University of California. All rights reserved. 6b528cefcSMark Murray * 7b528cefcSMark Murray * This code is derived from software contributed to Berkeley by 8b528cefcSMark Murray * Guido van Rossum. 9b528cefcSMark Murray * 10b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without 11b528cefcSMark Murray * modification, are permitted provided that the following conditions 12b528cefcSMark Murray * are met: 13b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright 14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer. 15b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright 16b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the 17b528cefcSMark Murray * documentation and/or other materials provided with the distribution. 18b528cefcSMark Murray * 3. All advertising materials mentioning features or use of this software 19b528cefcSMark Murray * must display the following acknowledgement: 20b528cefcSMark Murray * This product includes software developed by the University of 21b528cefcSMark Murray * California, Berkeley and its contributors. 22b528cefcSMark Murray * 4. Neither the name of the University nor the names of its contributors 23b528cefcSMark Murray * may be used to endorse or promote products derived from this software 24b528cefcSMark Murray * without specific prior written permission. 25b528cefcSMark Murray * 26b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36b528cefcSMark Murray * SUCH DAMAGE. 37b528cefcSMark Murray */ 38b528cefcSMark Murray 39b528cefcSMark Murray #if defined(LIBC_SCCS) && !defined(lint) 40b528cefcSMark Murray #if 0 41b528cefcSMark Murray static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; 42b528cefcSMark Murray #else 43b528cefcSMark Murray static char rcsid[] = "$NetBSD: fnmatch.c,v 1.11 1995/02/27 03:43:06 cgd Exp $"; 44b528cefcSMark Murray #endif 45b528cefcSMark Murray #endif /* LIBC_SCCS and not lint */ 46b528cefcSMark Murray 47b528cefcSMark Murray /* 48b528cefcSMark Murray * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. 49b528cefcSMark Murray * Compares a filename or pathname to a pattern. 50b528cefcSMark Murray */ 51b528cefcSMark Murray 52b528cefcSMark Murray #include <fnmatch.h> 53b528cefcSMark Murray #include <string.h> 54b528cefcSMark Murray 55b528cefcSMark Murray #define EOS '\0' 56b528cefcSMark Murray 57b528cefcSMark Murray static const char *rangematch (const char *, int, int); 58b528cefcSMark Murray 59b528cefcSMark Murray int 60b528cefcSMark Murray fnmatch(const char *pattern, const char *string, int flags) 61b528cefcSMark Murray { 62b528cefcSMark Murray const char *stringstart; 63b528cefcSMark Murray char c, test; 64b528cefcSMark Murray 65b528cefcSMark Murray for (stringstart = string;;) 66b528cefcSMark Murray switch (c = *pattern++) { 67b528cefcSMark Murray case EOS: 68b528cefcSMark Murray return (*string == EOS ? 0 : FNM_NOMATCH); 69b528cefcSMark Murray case '?': 70b528cefcSMark Murray if (*string == EOS) 71b528cefcSMark Murray return (FNM_NOMATCH); 72b528cefcSMark Murray if (*string == '/' && (flags & FNM_PATHNAME)) 73b528cefcSMark Murray return (FNM_NOMATCH); 74b528cefcSMark Murray if (*string == '.' && (flags & FNM_PERIOD) && 75b528cefcSMark Murray (string == stringstart || 76b528cefcSMark Murray ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) 77b528cefcSMark Murray return (FNM_NOMATCH); 78b528cefcSMark Murray ++string; 79b528cefcSMark Murray break; 80b528cefcSMark Murray case '*': 81b528cefcSMark Murray c = *pattern; 82b528cefcSMark Murray /* Collapse multiple stars. */ 83b528cefcSMark Murray while (c == '*') 84b528cefcSMark Murray c = *++pattern; 85b528cefcSMark Murray 86b528cefcSMark Murray if (*string == '.' && (flags & FNM_PERIOD) && 87b528cefcSMark Murray (string == stringstart || 88b528cefcSMark Murray ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) 89b528cefcSMark Murray return (FNM_NOMATCH); 90b528cefcSMark Murray 91b528cefcSMark Murray /* Optimize for pattern with * at end or before /. */ 92b528cefcSMark Murray if (c == EOS) 93b528cefcSMark Murray if (flags & FNM_PATHNAME) 94b528cefcSMark Murray return (strchr(string, '/') == NULL ? 95b528cefcSMark Murray 0 : FNM_NOMATCH); 96b528cefcSMark Murray else 97b528cefcSMark Murray return (0); 98b528cefcSMark Murray else if (c == '/' && flags & FNM_PATHNAME) { 99b528cefcSMark Murray if ((string = strchr(string, '/')) == NULL) 100b528cefcSMark Murray return (FNM_NOMATCH); 101b528cefcSMark Murray break; 102b528cefcSMark Murray } 103b528cefcSMark Murray 104b528cefcSMark Murray /* General case, use recursion. */ 105b528cefcSMark Murray while ((test = *string) != EOS) { 106b528cefcSMark Murray if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) 107b528cefcSMark Murray return (0); 108b528cefcSMark Murray if (test == '/' && flags & FNM_PATHNAME) 109b528cefcSMark Murray break; 110b528cefcSMark Murray ++string; 111b528cefcSMark Murray } 112b528cefcSMark Murray return (FNM_NOMATCH); 113b528cefcSMark Murray case '[': 114b528cefcSMark Murray if (*string == EOS) 115b528cefcSMark Murray return (FNM_NOMATCH); 116b528cefcSMark Murray if (*string == '/' && flags & FNM_PATHNAME) 117b528cefcSMark Murray return (FNM_NOMATCH); 118b528cefcSMark Murray if ((pattern = 119b528cefcSMark Murray rangematch(pattern, *string, flags)) == NULL) 120b528cefcSMark Murray return (FNM_NOMATCH); 121b528cefcSMark Murray ++string; 122b528cefcSMark Murray break; 123b528cefcSMark Murray case '\\': 124b528cefcSMark Murray if (!(flags & FNM_NOESCAPE)) { 125b528cefcSMark Murray if ((c = *pattern++) == EOS) { 126b528cefcSMark Murray c = '\\'; 127b528cefcSMark Murray --pattern; 128b528cefcSMark Murray } 129b528cefcSMark Murray } 130b528cefcSMark Murray /* FALLTHROUGH */ 131b528cefcSMark Murray default: 132b528cefcSMark Murray if (c != *string++) 133b528cefcSMark Murray return (FNM_NOMATCH); 134b528cefcSMark Murray break; 135b528cefcSMark Murray } 136b528cefcSMark Murray /* NOTREACHED */ 137b528cefcSMark Murray } 138b528cefcSMark Murray 139b528cefcSMark Murray static const char * 140b528cefcSMark Murray rangematch(const char *pattern, int test, int flags) 141b528cefcSMark Murray { 142b528cefcSMark Murray int negate, ok; 143b528cefcSMark Murray char c, c2; 144b528cefcSMark Murray 145b528cefcSMark Murray /* 146b528cefcSMark Murray * A bracket expression starting with an unquoted circumflex 147b528cefcSMark Murray * character produces unspecified results (IEEE 1003.2-1992, 148b528cefcSMark Murray * 3.13.2). This implementation treats it like '!', for 149b528cefcSMark Murray * consistency with the regular expression syntax. 150b528cefcSMark Murray * J.T. Conklin (conklin@ngai.kaleida.com) 151b528cefcSMark Murray */ 152b528cefcSMark Murray if (negate = (*pattern == '!' || *pattern == '^')) 153b528cefcSMark Murray ++pattern; 154b528cefcSMark Murray 155b528cefcSMark Murray for (ok = 0; (c = *pattern++) != ']';) { 156b528cefcSMark Murray if (c == '\\' && !(flags & FNM_NOESCAPE)) 157b528cefcSMark Murray c = *pattern++; 158b528cefcSMark Murray if (c == EOS) 159b528cefcSMark Murray return (NULL); 160b528cefcSMark Murray if (*pattern == '-' 161b528cefcSMark Murray && (c2 = *(pattern+1)) != EOS && c2 != ']') { 162b528cefcSMark Murray pattern += 2; 163b528cefcSMark Murray if (c2 == '\\' && !(flags & FNM_NOESCAPE)) 164b528cefcSMark Murray c2 = *pattern++; 165b528cefcSMark Murray if (c2 == EOS) 166b528cefcSMark Murray return (NULL); 167b528cefcSMark Murray if (c <= test && test <= c2) 168b528cefcSMark Murray ok = 1; 169b528cefcSMark Murray } else if (c == test) 170b528cefcSMark Murray ok = 1; 171b528cefcSMark Murray } 172b528cefcSMark Murray return (ok == negate ? NULL : pattern); 173b528cefcSMark Murray } 174