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 38static 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 62static inline int 63foldcase(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 73static const char * 74rangematch(const char *pattern, int test, int flags) 75{ 76 int negate, ok, need; 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 need = 1; 92 for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']' || need;) { 93 need = 0; 94 if (c == '/') 95 return (void *)-1; 96 if (c == '\\' && !(flags & FNM_NOESCAPE)) 97 c = FOLDCASE(*pattern++, flags); 98 if (c == EOS) 99 return NULL; 100 if (*pattern == '-' 101 && (c2 = FOLDCASE(*(pattern + 1), flags)) != EOS && 102 c2 != ']') { 103 pattern += 2; 104 if (c2 == '\\' && !(flags & FNM_NOESCAPE)) 105 c2 = FOLDCASE(*pattern++, flags); 106 if (c2 == EOS) 107 return NULL; 108 if (c <= test && test <= c2) 109 ok = 1; 110 } else if (c == test) 111 ok = 1; 112 } 113 return ok == negate ? NULL : pattern; 114} 115 116 117static int 118fnmatchx(const char *pattern, const char *string, int flags, size_t recursion) 119{ 120 const char *stringstart, *r; 121 char c, test; 122 123 _DIAGASSERT(pattern != NULL); 124 _DIAGASSERT(string != NULL); 125 126 if (recursion-- == 0) 127 return FNM_NORES; 128 129 for (stringstart = string;;) { 130 switch (c = FOLDCASE(*pattern++, flags)) { 131 case EOS: 132 if ((flags & FNM_LEADING_DIR) && *string == '/') 133 return 0; 134 return *string == EOS ? 0 : FNM_NOMATCH; 135 case '?': 136 if (*string == EOS) 137 return FNM_NOMATCH; 138 if (*string == '/' && (flags & FNM_PATHNAME)) 139 return FNM_NOMATCH; 140 if (*string == '.' && (flags & FNM_PERIOD) && 141 (string == stringstart || 142 ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) 143 return FNM_NOMATCH; 144 ++string; 145 break; 146 case '*': 147 c = FOLDCASE(*pattern, flags); 148 /* Collapse multiple stars. */ 149 while (c == '*') 150 c = FOLDCASE(*++pattern, flags); 151 152 if (*string == '.' && (flags & FNM_PERIOD) && 153 (string == stringstart || 154 ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) 155 return FNM_NOMATCH; 156 157 /* Optimize for pattern with * at end or before /. */ 158 if (c == EOS) { 159 if (flags & FNM_PATHNAME) 160 return (flags & FNM_LEADING_DIR) || 161 strchr(string, '/') == NULL ? 162 0 : FNM_NOMATCH; 163 else 164 return 0; 165 } else if (c == '/' && flags & FNM_PATHNAME) { 166 if ((string = strchr(string, '/')) == NULL) 167 return FNM_NOMATCH; 168 break; 169 } 170 171 /* General case, use recursion. */ 172 while ((test = FOLDCASE(*string, flags)) != EOS) { 173 int e; 174 switch ((e = fnmatchx(pattern, string, 175 flags & ~FNM_PERIOD, recursion))) { 176 case FNM_NOMATCH: 177 break; 178 default: 179 return e; 180 } 181 if (test == '/' && flags & FNM_PATHNAME) 182 break; 183 ++string; 184 } 185 return FNM_NOMATCH; 186 case '[': 187 if (*string == EOS) 188 return FNM_NOMATCH; 189 if (*string == '/' && flags & FNM_PATHNAME) 190 return FNM_NOMATCH; 191 if ((r = rangematch(pattern, 192 FOLDCASE(*string, flags), flags)) == NULL) 193 return FNM_NOMATCH; 194 if (r == (void *)-1) { 195 if (*string != '[') 196 return FNM_NOMATCH; 197 } else 198 pattern = r; 199 ++string; 200 break; 201 case '\\': 202 if (!(flags & FNM_NOESCAPE)) { 203 if ((c = FOLDCASE(*pattern++, flags)) == EOS) { 204 c = '\0'; 205 --pattern; 206 } 207 } 208 /* FALLTHROUGH */ 209 default: 210 if (c != FOLDCASE(*string++, flags)) 211 return FNM_NOMATCH; 212 break; 213 } 214 } 215 /* NOTREACHED */ 216} 217 218int 219fnmatch(const char *pattern, const char *string, int flags) 220{ 221 return fnmatchx(pattern, string, flags, 64); 222} 223