fnmatch.c revision 90045
1132720Skan/* 2132720Skan * Copyright (c) 1989, 1993, 1994 3132720Skan * The Regents of the University of California. All rights reserved. 4132720Skan * 5132720Skan * This code is derived from software contributed to Berkeley by 6132720Skan * Guido van Rossum. 7132720Skan * 8132720Skan * Redistribution and use in source and binary forms, with or without 9132720Skan * modification, are permitted provided that the following conditions 10132720Skan * are met: 11132720Skan * 1. Redistributions of source code must retain the above copyright 12132720Skan * notice, this list of conditions and the following disclaimer. 13132720Skan * 2. Redistributions in binary form must reproduce the above copyright 14132720Skan * notice, this list of conditions and the following disclaimer in the 15132720Skan * documentation and/or other materials provided with the distribution. 16132720Skan * 3. All advertising materials mentioning features or use of this software 17132720Skan * must display the following acknowledgement: 18132720Skan * This product includes software developed by the University of 19132720Skan * California, Berkeley and its contributors. 20132720Skan * 4. Neither the name of the University nor the names of its contributors 21132720Skan * may be used to endorse or promote products derived from this software 22132720Skan * without specific prior written permission. 23132720Skan * 24132720Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25132720Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26132720Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27132720Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28132720Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29132720Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30132720Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31132720Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32132720Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33132720Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34132720Skan * SUCH DAMAGE. 35132720Skan */ 36132720Skan 37132720Skan#if defined(LIBC_SCCS) && !defined(lint) 38132720Skanstatic char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; 39132720Skan#endif /* LIBC_SCCS and not lint */ 40132720Skan#include <sys/cdefs.h> 41132720Skan__FBSDID("$FreeBSD: head/lib/libc/gen/fnmatch.c 90045 2002-02-01 01:32:19Z obrien $"); 42132720Skan 43132720Skan/* 44132720Skan * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. 45132720Skan * Compares a filename or pathname to a pattern. 46132720Skan */ 47132720Skan 48132720Skan#include <ctype.h> 49132720Skan#include <fnmatch.h> 50132720Skan#include <string.h> 51132720Skan#include <stdio.h> 52132720Skan 53132720Skan#include "collate.h" 54132720Skan 55132720Skan#define EOS '\0' 56132720Skan 57132720Skan#define RANGE_MATCH 1 58132720Skan#define RANGE_NOMATCH 0 59132720Skan#define RANGE_ERROR (-1) 60132720Skan 61132720Skanstatic int rangematch(const char *, char, int, char **); 62132720Skan 63132720Skanint 64132720Skanfnmatch(pattern, string, flags) 65132720Skan const char *pattern, *string; 66132720Skan int flags; 67132720Skan{ 68132720Skan const char *stringstart; 69132720Skan char *newp; 70132720Skan char c, test; 71132720Skan 72132720Skan for (stringstart = string;;) 73132720Skan switch (c = *pattern++) { 74132720Skan case EOS: 75132720Skan if ((flags & FNM_LEADING_DIR) && *string == '/') 76132720Skan return (0); 77132720Skan return (*string == EOS ? 0 : FNM_NOMATCH); 78132720Skan case '?': 79132720Skan if (*string == EOS) 80132720Skan return (FNM_NOMATCH); 81132720Skan if (*string == '/' && (flags & FNM_PATHNAME)) 82132720Skan return (FNM_NOMATCH); 83132720Skan if (*string == '.' && (flags & FNM_PERIOD) && 84132720Skan (string == stringstart || 85132720Skan ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) 86132720Skan return (FNM_NOMATCH); 87132720Skan ++string; 88132720Skan break; 89132720Skan case '*': 90132720Skan c = *pattern; 91132720Skan /* Collapse multiple stars. */ 92132720Skan while (c == '*') 93132720Skan c = *++pattern; 94132720Skan 95132720Skan if (*string == '.' && (flags & FNM_PERIOD) && 96132720Skan (string == stringstart || 97132720Skan ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) 98132720Skan return (FNM_NOMATCH); 99132720Skan 100132720Skan /* Optimize for pattern with * at end or before /. */ 101132720Skan if (c == EOS) 102132720Skan if (flags & FNM_PATHNAME) 103132720Skan return ((flags & FNM_LEADING_DIR) || 104132720Skan strchr(string, '/') == NULL ? 105132720Skan 0 : FNM_NOMATCH); 106132720Skan else 107132720Skan return (0); 108132720Skan else if (c == '/' && flags & FNM_PATHNAME) { 109132720Skan if ((string = strchr(string, '/')) == NULL) 110132720Skan return (FNM_NOMATCH); 111132720Skan break; 112132720Skan } 113132720Skan 114132720Skan /* General case, use recursion. */ 115132720Skan while ((test = *string) != EOS) { 116132720Skan if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) 117132720Skan return (0); 118132720Skan if (test == '/' && flags & FNM_PATHNAME) 119132720Skan break; 120132720Skan ++string; 121132720Skan } 122132720Skan return (FNM_NOMATCH); 123132720Skan case '[': 124132720Skan if (*string == EOS) 125132720Skan return (FNM_NOMATCH); 126132720Skan if (*string == '/' && (flags & FNM_PATHNAME)) 127132720Skan return (FNM_NOMATCH); 128132720Skan if (*string == '.' && (flags & FNM_PERIOD) && 129132720Skan (string == stringstart || 130132720Skan ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) 131132720Skan return (FNM_NOMATCH); 132132720Skan 133132720Skan switch (rangematch(pattern, *string, flags, &newp)) { 134132720Skan case RANGE_ERROR: 135132720Skan goto norm; 136132720Skan case RANGE_MATCH: 137132720Skan pattern = newp; 138132720Skan break; 139132720Skan case RANGE_NOMATCH: 140132720Skan return (FNM_NOMATCH); 141132720Skan } 142132720Skan ++string; 143132720Skan break; 144132720Skan case '\\': 145132720Skan if (!(flags & FNM_NOESCAPE)) { 146132720Skan if ((c = *pattern++) == EOS) { 147132720Skan c = '\\'; 148132720Skan --pattern; 149132720Skan } 150132720Skan } 151132720Skan /* FALLTHROUGH */ 152132720Skan default: 153132720Skan norm: 154132720Skan if (c == *string) 155132720Skan ; 156132720Skan else if ((flags & FNM_CASEFOLD) && 157132720Skan (tolower((unsigned char)c) == 158132720Skan tolower((unsigned char)*string))) 159132720Skan ; 160132720Skan else 161132720Skan return (FNM_NOMATCH); 162132720Skan string++; 163132720Skan break; 164132720Skan } 165132720Skan /* NOTREACHED */ 166132720Skan} 167132720Skan 168132720Skanstatic int 169132720Skanrangematch(pattern, test, flags, newp) 170132720Skan const char *pattern; 171132720Skan char test; 172132720Skan int flags; 173132720Skan char **newp; 174132720Skan{ 175132720Skan int negate, ok; 176132720Skan char c, c2; 177132720Skan 178132720Skan /* 179132720Skan * A bracket expression starting with an unquoted circumflex 180132720Skan * character produces unspecified results (IEEE 1003.2-1992, 181132720Skan * 3.13.2). This implementation treats it like '!', for 182132720Skan * consistency with the regular expression syntax. 183132720Skan * J.T. Conklin (conklin@ngai.kaleida.com) 184132720Skan */ 185132720Skan if ( (negate = (*pattern == '!' || *pattern == '^')) ) 186132720Skan ++pattern; 187132720Skan 188132720Skan if (flags & FNM_CASEFOLD) 189132720Skan test = tolower((unsigned char)test); 190132720Skan 191132720Skan /* 192132720Skan * A right bracket shall lose its special meaning and represent 193132720Skan * itself in a bracket expression if it occurs first in the list. 194132720Skan * -- POSIX.2 2.8.3.2 195132720Skan */ 196132720Skan ok = 0; 197132720Skan c = *pattern++; 198132720Skan do { 199132720Skan if (c == '\\' && !(flags & FNM_NOESCAPE)) 200132720Skan c = *pattern++; 201132720Skan if (c == EOS) 202132720Skan return (RANGE_ERROR); 203132720Skan 204132720Skan if (c == '/' && (flags & FNM_PATHNAME)) 205132720Skan return (RANGE_NOMATCH); 206132720Skan 207132720Skan if (flags & FNM_CASEFOLD) 208132720Skan c = tolower((unsigned char)c); 209132720Skan 210132720Skan if (*pattern == '-' 211132720Skan && (c2 = *(pattern+1)) != EOS && c2 != ']') { 212132720Skan pattern += 2; 213132720Skan if (c2 == '\\' && !(flags & FNM_NOESCAPE)) 214132720Skan c2 = *pattern++; 215132720Skan if (c2 == EOS) 216132720Skan return (RANGE_ERROR); 217132720Skan 218132720Skan if (flags & FNM_CASEFOLD) 219132720Skan c2 = tolower((unsigned char)c2); 220132720Skan 221132720Skan if (__collate_load_error ? 222132720Skan c <= test && test <= c2 : 223132720Skan __collate_range_cmp(c, test) <= 0 224132720Skan && __collate_range_cmp(test, c2) <= 0 225132720Skan ) 226132720Skan ok = 1; 227132720Skan } else if (c == test) 228132720Skan ok = 1; 229132720Skan } while ((c = *pattern++) != ']'); 230132720Skan 231132720Skan *newp = (char *)pattern; 232132720Skan return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH); 233132720Skan} 234132720Skan