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