fnmatch.c revision 17552
123599Smarkm/* 251694Sroger * Copyright (c) 1989, 1993, 1994 351694Sroger * The Regents of the University of California. All rights reserved. 448781Sroger * 548781Sroger * This code is derived from software contributed to Berkeley by 623599Smarkm * Guido van Rossum. 723599Smarkm * 823599Smarkm * Redistribution and use in source and binary forms, with or without 923599Smarkm * modification, are permitted provided that the following conditions 1023599Smarkm * are met: 1123599Smarkm * 1. Redistributions of source code must retain the above copyright 1223599Smarkm * notice, this list of conditions and the following disclaimer. 1323599Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1423599Smarkm * notice, this list of conditions and the following disclaimer in the 1523599Smarkm * documentation and/or other materials provided with the distribution. 1623599Smarkm * 3. All advertising materials mentioning features or use of this software 1723599Smarkm * must display the following acknowledgement: 1823599Smarkm * This product includes software developed by the University of 1923599Smarkm * California, Berkeley and its contributors. 2023599Smarkm * 4. Neither the name of the University nor the names of its contributors 2123599Smarkm * may be used to endorse or promote products derived from this software 2223599Smarkm * without specific prior written permission. 2323599Smarkm * 2423599Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2523599Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2623599Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2723599Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2823599Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2923599Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3023599Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3123599Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3223599Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3323599Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3439838Ssos * SUCH DAMAGE. 3523599Smarkm */ 3651694Sroger 3759014Sroger#if defined(LIBC_SCCS) && !defined(lint) 3859014Srogerstatic char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; 3959014Sroger#endif /* LIBC_SCCS and not lint */ 4059014Sroger 4162112Sroger/* 4262112Sroger * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. 4362112Sroger * Compares a filename or pathname to a pattern. 4462112Sroger */ 4562112Sroger 4651694Sroger#include <fnmatch.h> 4751694Sroger#include <locale.h> 4862112Sroger#include <string.h> 4962112Sroger 5062112Sroger#define EOS '\0' 5162112Sroger 5262112Srogerstatic const char *rangematch __P((const char *, int, int)); 5362112Sroger 5467306Srogerint 5567306Srogerfnmatch(pattern, string, flags) 5667306Sroger const char *pattern, *string; 5767306Sroger int flags; 5862112Sroger{ 5962112Sroger const char *stringstart; 6062112Sroger char c, test; 6162112Sroger 6262112Sroger for (stringstart = string;;) 6362112Sroger switch (c = *pattern++) { 6462112Sroger case EOS: 6562112Sroger return (*string == EOS ? 0 : FNM_NOMATCH); 6662112Sroger case '?': 6762112Sroger if (*string == EOS) 6862112Sroger return (FNM_NOMATCH); 6962112Sroger if (*string == '/' && (flags & FNM_PATHNAME)) 7062112Sroger return (FNM_NOMATCH); 7162112Sroger if (*string == '.' && (flags & FNM_PERIOD) && 7262112Sroger (string == stringstart || 7362112Sroger ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) 7462112Sroger return (FNM_NOMATCH); 7562112Sroger ++string; 7662112Sroger break; 7762112Sroger case '*': 7862112Sroger c = *pattern; 7962112Sroger /* Collapse multiple stars. */ 8062112Sroger while (c == '*') 8123599Smarkm c = *++pattern; 8223599Smarkm 8323599Smarkm if (*string == '.' && (flags & FNM_PERIOD) && 8423599Smarkm (string == stringstart || 8523599Smarkm ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) 8647884Sroger return (FNM_NOMATCH); 8723599Smarkm 8867306Sroger /* Optimize for pattern with * at end or before /. */ 8967306Sroger if (c == EOS) 9067306Sroger if (flags & FNM_PATHNAME) 9167306Sroger return (strchr(string, '/') == NULL ? 9267306Sroger 0 : FNM_NOMATCH); 9323599Smarkm else 9467306Sroger return (0); 9567306Sroger else if (c == '/' && flags & FNM_PATHNAME) { 9667306Sroger if ((string = strchr(string, '/')) == NULL) 9767306Sroger return (FNM_NOMATCH); 9867306Sroger break; 9967306Sroger } 10067306Sroger 10167306Sroger /* General case, use recursion. */ 10267306Sroger while ((test = *string) != EOS) { 10367306Sroger if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) 10467306Sroger return (0); 10567306Sroger if (test == '/' && flags & FNM_PATHNAME) 10667306Sroger break; 10767306Sroger ++string; 10843771Sroger } 10943771Sroger return (FNM_NOMATCH); 11047492Sroger case '[': 11143771Sroger if (*string == EOS) 11243771Sroger return (FNM_NOMATCH); 11343771Sroger if (*string == '/' && flags & FNM_PATHNAME) 11424246Sfsmp return (FNM_NOMATCH); 11524246Sfsmp if ((pattern = 11624246Sfsmp rangematch(pattern, *string, flags)) == NULL) 11724246Sfsmp return (FNM_NOMATCH); 11824246Sfsmp ++string; 11924246Sfsmp break; 12024246Sfsmp case '\\': 12124246Sfsmp if (!(flags & FNM_NOESCAPE)) { 12224246Sfsmp if ((c = *pattern++) == EOS) { 12323599Smarkm c = '\\'; 12424246Sfsmp --pattern; 12524246Sfsmp } 12624528Sfsmp } 12724528Sfsmp /* FALLTHROUGH */ 12824528Sfsmp default: 12924528Sfsmp if (c != *string++) 13024528Sfsmp return (FNM_NOMATCH); 13138707Ssos break; 13224528Sfsmp } 13324528Sfsmp /* NOTREACHED */ 13424246Sfsmp} 13524528Sfsmp 13624528Sfsmpstatic const char * 13724528Sfsmprangematch(pattern, test, flags) 13824528Sfsmp const char *pattern; 13937611Sahasty int test, flags; 14024528Sfsmp{ 14124528Sfsmp int negate, ok; 14224528Sfsmp char c, c2; 14324528Sfsmp 14424528Sfsmp /* 14524528Sfsmp * A bracket expression starting with an unquoted circumflex 14624246Sfsmp * character produces unspecified results (IEEE 1003.2-1992, 14724246Sfsmp * 3.13.2). This implementation treats it like '!', for 14824246Sfsmp * consistency with the regular expression syntax. 14924246Sfsmp * J.T. Conklin (conklin@ngai.kaleida.com) 15024246Sfsmp */ 15124246Sfsmp if ( (negate = (*pattern == '!' || *pattern == '^')) ) 15224246Sfsmp ++pattern; 15324246Sfsmp 15424246Sfsmp for (ok = 0; (c = *pattern++) != ']';) { 15524246Sfsmp if (c == '\\' && !(flags & FNM_NOESCAPE)) 15624528Sfsmp c = *pattern++; 15724528Sfsmp if (c == EOS) 15824528Sfsmp return (NULL); 15924528Sfsmp if (*pattern == '-' 16024528Sfsmp && (c2 = *(pattern+1)) != EOS && c2 != ']') { 16124528Sfsmp pattern += 2; 16224528Sfsmp if (c2 == '\\' && !(flags & FNM_NOESCAPE)) 16324528Sfsmp c2 = *pattern++; 16424246Sfsmp if (c2 == EOS) 16524246Sfsmp return (NULL); 16624246Sfsmp if ( collate_range_cmp(c, test) <= 0 16724246Sfsmp && collate_range_cmp(test, c2) <= 0 16824246Sfsmp ) 16924528Sfsmp ok = 1; 17024528Sfsmp } else if (c == test) 17124528Sfsmp ok = 1; 17224528Sfsmp } 17324528Sfsmp return (ok == negate ? NULL : pattern); 17424528Sfsmp} 17524528Sfsmp