fnmatch.c

00001 /*      $NetBSD: fnmatch.c,v 1.20 2003/08/07 16:42:48 agc Exp $ */
00002 
00003 /*
00004  * Copyright (c) 1989, 1993, 1994
00005  *      The Regents of the University of California.  All rights reserved.
00006  *
00007  * This code is derived from software contributed to Berkeley by
00008  * Guido van Rossum.
00009  *
00010  * Redistribution and use in source and binary forms, with or without
00011  * modification, are permitted provided that the following conditions
00012  * are met:
00013  * 1. Redistributions of source code must retain the above copyright
00014  *    notice, this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright
00016  *    notice, this list of conditions and the following disclaimer in the
00017  *    documentation and/or other materials provided with the distribution.
00018  * 3. Neither the name of the University nor the names of its contributors
00019  *    may be used to endorse or promote products derived from this software
00020  *    without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  */
00034 
00035 /*
00036  * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
00037  * Compares a filename or pathname to a pattern.
00038  */
00039 
00040 #include <u/missing/fnmatch.h>
00041 
00042 #include <ctype.h>
00043 #include <string.h>
00044 
00045 #define EOS     '\0'
00046 
00047 static const char *rangematch(const char *, int, int);
00048 
00049 static inline int foldcase(int ch, int flags)
00050 {
00051 
00052         if ((flags & FNM_CASEFOLD) != 0 && isupper(ch))
00053                 return (tolower(ch));
00054         return (ch);
00055 }
00056 
00057 #define FOLDCASE(ch, flags)     foldcase((unsigned char)(ch), (flags))
00058 
00059 int fnmatch (const char *pattern, const char *string, int flags)
00060 {
00061         const char *stringstart;
00062         char c, test;
00063 
00064         for (stringstart = string;;)
00065                 switch (c = FOLDCASE(*pattern++, flags)) {
00066                 case EOS:
00067                         if ((flags & FNM_LEADING_DIR) && *string == '/')
00068                                 return (0);
00069                         return (*string == EOS ? 0 : FNM_NOMATCH);
00070                 case '?':
00071                         if (*string == EOS)
00072                                 return (FNM_NOMATCH);
00073                         if (*string == '/' && (flags & FNM_PATHNAME))
00074                                 return (FNM_NOMATCH);
00075                         if (*string == '.' && (flags & FNM_PERIOD) &&
00076                             (string == stringstart ||
00077                             ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
00078                                 return (FNM_NOMATCH);
00079                         ++string;
00080                         break;
00081                 case '*':
00082                         c = FOLDCASE(*pattern, flags);
00083                         /* Collapse multiple stars. */
00084                         while (c == '*')
00085                                 c = FOLDCASE(*++pattern, flags);
00086 
00087                         if (*string == '.' && (flags & FNM_PERIOD) &&
00088                             (string == stringstart ||
00089                             ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
00090                                 return (FNM_NOMATCH);
00091 
00092                         /* Optimize for pattern with * at end or before /. */
00093                         if (c == EOS) {
00094                                 if (flags & FNM_PATHNAME)
00095                                         return ((flags & FNM_LEADING_DIR) ||
00096                                             strchr(string, '/') == NULL ?
00097                                             0 : FNM_NOMATCH);
00098                                 else
00099                                         return (0);
00100                         } else if (c == '/' && flags & FNM_PATHNAME) {
00101                                 if ((string = strchr(string, '/')) == NULL)
00102                                         return (FNM_NOMATCH);
00103                                 break;
00104                         }
00105 
00106                         /* General case, use recursion. */
00107                         while ((test = FOLDCASE(*string, flags)) != EOS) {
00108                                 if (!fnmatch(pattern, string,
00109                                              flags & ~FNM_PERIOD))
00110                                         return (0);
00111                                 if (test == '/' && flags & FNM_PATHNAME)
00112                                         break;
00113                                 ++string;
00114                         }
00115                         return (FNM_NOMATCH);
00116                 case '[':
00117                         if (*string == EOS)
00118                                 return (FNM_NOMATCH);
00119                         if (*string == '/' && flags & FNM_PATHNAME)
00120                                 return (FNM_NOMATCH);
00121                         if ((pattern =
00122                             rangematch(pattern, FOLDCASE(*string, flags),
00123                                        flags)) == NULL)
00124                                 return (FNM_NOMATCH);
00125                         ++string;
00126                         break;
00127                 case '\\':
00128                         if (!(flags & FNM_NOESCAPE)) {
00129                                 if ((c = FOLDCASE(*pattern++, flags)) == EOS) {
00130                                         c = '\\';
00131                                         --pattern;
00132                                 }
00133                         }
00134                         /* FALLTHROUGH */
00135                 default:
00136                         if (c != FOLDCASE(*string++, flags))
00137                                 return (FNM_NOMATCH);
00138                         break;
00139                 }
00140         /* NOTREACHED */
00141 }
00142 
00143 static const char *rangematch (const char *pattern, int test, int flags)
00144 {
00145         int negate, ok;
00146         char c, c2;
00147 
00148         /*
00149          * A bracket expression starting with an unquoted circumflex
00150          * character produces unspecified results (IEEE 1003.2-1992,
00151          * 3.13.2).  This implementation treats it like '!', for
00152          * consistency with the regular expression syntax.
00153          * J.T. Conklin (conklin@ngai.kaleida.com)
00154          */
00155         if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
00156                 ++pattern;
00157         
00158         for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) {
00159                 if (c == '\\' && !(flags & FNM_NOESCAPE))
00160                         c = FOLDCASE(*pattern++, flags);
00161                 if (c == EOS)
00162                         return (NULL);
00163                 if (*pattern == '-' 
00164                     && (c2 = FOLDCASE(*(pattern+1), flags)) != EOS &&
00165                         c2 != ']') {
00166                         pattern += 2;
00167                         if (c2 == '\\' && !(flags & FNM_NOESCAPE))
00168                                 c2 = FOLDCASE(*pattern++, flags);
00169                         if (c2 == EOS)
00170                                 return (NULL);
00171                         if (c <= test && test <= c2)
00172                                 ok = 1;
00173                 } else if (c == test)
00174                         ok = 1;
00175         }
00176         return (ok == negate ? NULL : pattern);
00177 }

←Products
© 2005-2012 - KoanLogic S.r.l. - All rights reserved