fnmatch.c revision 19132
1329099Skevans/* 2185222Ssam * Copyright (c) 1989, 1993, 1994 3330449Seadler * The Regents of the University of California. All rights reserved. 4330449Seadler * 5330449Seadler * This code is derived from software contributed to Berkeley by 6185222Ssam * Guido van Rossum. 7185222Ssam * 8185222Ssam * Redistribution and use in source and binary forms, with or without 9185222Ssam * modification, are permitted provided that the following conditions 10185222Ssam * are met: 11185222Ssam * 1. Redistributions of source code must retain the above copyright 12185222Ssam * notice, this list of conditions and the following disclaimer. 13185222Ssam * 2. Redistributions in binary form must reproduce the above copyright 14185222Ssam * notice, this list of conditions and the following disclaimer in the 15185222Ssam * documentation and/or other materials provided with the distribution. 16185222Ssam * 3. All advertising materials mentioning features or use of this software 17185222Ssam * must display the following acknowledgement: 18185222Ssam * This product includes software developed by the University of 19185222Ssam * California, Berkeley and its contributors. 20185222Ssam * 4. Neither the name of the University nor the names of its contributors 21185222Ssam * may be used to endorse or promote products derived from this software 22185222Ssam * without specific prior written permission. 23185222Ssam * 24185222Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25185222Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26185222Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27185222Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28185222Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29185222Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30185222Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31185222Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32185222Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33185222Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34185222Ssam * SUCH DAMAGE. 35185222Ssam */ 36185222Ssam 37185222Ssam#if defined(LIBC_SCCS) && !defined(lint) 38185222Ssamstatic char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; 39185222Ssam#endif /* LIBC_SCCS and not lint */ 40185222Ssam 41186334Ssam/* 42185222Ssam * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. 43185222Ssam * Compares a filename or pathname to a pattern. 44185222Ssam */ 45185222Ssam 46185222Ssam#include <ctype.h> 47185222Ssam#include <fnmatch.h> 48185222Ssam#include <locale.h> 49185222Ssam#include <string.h> 50185222Ssam#include <stdio.h> 51332981Sbenno 52185222Ssam#define EOS '\0' 53185222Ssam 54185222Ssamstatic const char *rangematch __P((const char *, char, int)); 55185222Ssam 56185222Ssamint 57185222Ssamfnmatch(pattern, string, flags) 58185222Ssam const char *pattern, *string; 59185222Ssam int flags; 60185222Ssam{ 61185222Ssam const char *stringstart; 62185222Ssam char c, test; 63185222Ssam 64185222Ssam for (stringstart = string;;) 65185222Ssam switch (c = *pattern++) { 66329099Skevans case EOS: 67329099Skevans if ((flags & FNM_LEADING_DIR) && *string == '/') 68185222Ssam return (0); 69185222Ssam return (*string == EOS ? 0 : FNM_NOMATCH); 70185222Ssam case '?': 71329099Skevans if (*string == EOS) 72185222Ssam return (FNM_NOMATCH); 73185222Ssam if (*string == '/' && (flags & FNM_PATHNAME)) 74185222Ssam return (FNM_NOMATCH); 75185222Ssam if (*string == '.' && (flags & FNM_PERIOD) && 76185222Ssam (string == stringstart || 77185222Ssam ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) 78185222Ssam return (FNM_NOMATCH); 79329099Skevans ++string; 80185222Ssam break; 81185222Ssam case '*': 82185222Ssam c = *pattern; 83185222Ssam /* Collapse multiple stars. */ 84185222Ssam while (c == '*') 85185222Ssam c = *++pattern; 86185222Ssam 87185222Ssam if (*string == '.' && (flags & FNM_PERIOD) && 88185222Ssam (string == stringstart || 89185222Ssam ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) 90185222Ssam return (FNM_NOMATCH); 91185222Ssam 92185222Ssam /* Optimize for pattern with * at end or before /. */ 93185222Ssam if (c == EOS) 94185222Ssam if (flags & FNM_PATHNAME) 95185222Ssam return (strchr(string, '/') == NULL ? 96185222Ssam 0 : FNM_NOMATCH); 97185222Ssam else 98185222Ssam return (0); 99185222Ssam else if (c == '/' && flags & FNM_PATHNAME) { 100185222Ssam if ((string = strchr(string, '/')) == NULL) 101185222Ssam return (FNM_NOMATCH); 102185222Ssam break; 103329099Skevans } 104185222Ssam 105185222Ssam /* General case, use recursion. */ 106185222Ssam while ((test = *string) != EOS) { 107185222Ssam if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) 108185222Ssam return (0); 109185222Ssam if (test == '/' && flags & FNM_PATHNAME) 110185222Ssam break; 111185222Ssam ++string; 112185222Ssam } 113185222Ssam return (FNM_NOMATCH); 114185222Ssam case '[': 115185222Ssam if (*string == EOS) 116185222Ssam return (FNM_NOMATCH); 117185222Ssam if (*string == '/' && flags & FNM_PATHNAME) 118185222Ssam return (FNM_NOMATCH); 119185222Ssam if ((pattern = 120185222Ssam rangematch(pattern, *string, flags)) == NULL) 121185222Ssam return (FNM_NOMATCH); 122185222Ssam ++string; 123185222Ssam break; 124185222Ssam case '\\': 125185222Ssam if (!(flags & FNM_NOESCAPE)) { 126214921Scognet if ((c = *pattern++) == EOS) { 127185222Ssam c = '\\'; 128185222Ssam --pattern; 129185222Ssam } 130185222Ssam } 131185222Ssam /* FALLTHROUGH */ 132185222Ssam default: 133185222Ssam if (c == *string) 134185222Ssam ; 135185222Ssam else if ((flags & FNM_CASEFOLD) && 136185222Ssam (tolower((unsigned char)c) == 137185222Ssam tolower((unsigned char)*string))) 138185222Ssam ; 139185222Ssam else 140185222Ssam return (FNM_NOMATCH); 141185222Ssam string++; 142185222Ssam break; 143185222Ssam } 144185222Ssam /* NOTREACHED */ 145185222Ssam} 146185222Ssam 147185222Ssamstatic const char * 148185222Ssamrangematch(pattern, test, flags) 149185222Ssam const char *pattern; 150185222Ssam char test; 151185222Ssam int flags; 152185222Ssam{ 153185222Ssam int negate, ok; 154185222Ssam char c, c2; 155185222Ssam 156185222Ssam /* 157185222Ssam * A bracket expression starting with an unquoted circumflex 158185222Ssam * character produces unspecified results (IEEE 1003.2-1992, 159185222Ssam * 3.13.2). This implementation treats it like '!', for 160185222Ssam * consistency with the regular expression syntax. 161185222Ssam * J.T. Conklin (conklin@ngai.kaleida.com) 162185222Ssam */ 163185222Ssam if ( (negate = (*pattern == '!' || *pattern == '^')) ) 164185222Ssam ++pattern; 165185222Ssam 166185222Ssam if (flags & FNM_CASEFOLD) 167185222Ssam test = tolower((unsigned char)test); 168214921Scognet 169185222Ssam for (ok = 0; (c = *pattern++) != ']';) { 170185222Ssam if (c == '\\' && !(flags & FNM_NOESCAPE)) 171185222Ssam c = *pattern++; 172185222Ssam if (c == EOS) 173185222Ssam return (NULL); 174185222Ssam 175185222Ssam if (flags & FNM_CASEFOLD) 176185222Ssam c = tolower((unsigned char)c); 177185222Ssam 178185222Ssam if (*pattern == '-' 179185222Ssam && (c2 = *(pattern+1)) != EOS && c2 != ']') { 180185222Ssam pattern += 2; 181185222Ssam if (c2 == '\\' && !(flags & FNM_NOESCAPE)) 182329099Skevans c2 = *pattern++; 183329099Skevans if (c2 == EOS) 184185222Ssam return (NULL); 185185222Ssam 186185222Ssam if (flags & FNM_CASEFOLD) 187185222Ssam c2 = tolower((unsigned char)c2); 188329099Skevans 189329099Skevans if ( collate_range_cmp(c, test) <= 0 190185222Ssam && collate_range_cmp(test, c2) <= 0 191329099Skevans ) 192185222Ssam ok = 1; 193185222Ssam } else if (c == test) 194185222Ssam ok = 1; 195185222Ssam } 196185222Ssam return (ok == negate ? NULL : pattern); 197185222Ssam} 198185222Ssam