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