Main Page | Modules | Data Structures | File List | Data Fields

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 <missing/fnmatch.h>
00041 
00042 #include <assert.h>
00043 #include <ctype.h>
00044 #include <string.h>
00045 
00046 #define EOS     '\0'
00047 
00048 static const char *rangematch(const char *, int, int);
00049 
00050 static inline int
00051 foldcase(int ch, int flags)
00052 {
00053 
00054         if ((flags & FNM_CASEFOLD) != 0 && isupper(ch))
00055                 return (tolower(ch));
00056         return (ch);
00057 }
00058 
00059 #define FOLDCASE(ch, flags)     foldcase((unsigned char)(ch), (flags))
00060 
00061 int
00062 fnmatch(pattern, string, flags)
00063         const char *pattern, *string;
00064         int flags;
00065 {
00066         const char *stringstart;
00067         char c, test;
00068 
00069         for (stringstart = string;;)
00070                 switch (c = FOLDCASE(*pattern++, flags)) {
00071                 case EOS:
00072                         if ((flags & FNM_LEADING_DIR) && *string == '/')
00073                                 return (0);
00074                         return (*string == EOS ? 0 : FNM_NOMATCH);
00075                 case '?':
00076                         if (*string == EOS)
00077                                 return (FNM_NOMATCH);
00078                         if (*string == '/' && (flags & FNM_PATHNAME))
00079                                 return (FNM_NOMATCH);
00080                         if (*string == '.' && (flags & FNM_PERIOD) &&
00081                             (string == stringstart ||
00082                             ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
00083                                 return (FNM_NOMATCH);
00084                         ++string;
00085                         break;
00086                 case '*':
00087                         c = FOLDCASE(*pattern, flags);
00088                         /* Collapse multiple stars. */
00089                         while (c == '*')
00090                                 c = FOLDCASE(*++pattern, flags);
00091 
00092                         if (*string == '.' && (flags & FNM_PERIOD) &&
00093                             (string == stringstart ||
00094                             ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
00095                                 return (FNM_NOMATCH);
00096 
00097                         /* Optimize for pattern with * at end or before /. */
00098                         if (c == EOS) {
00099                                 if (flags & FNM_PATHNAME)
00100                                         return ((flags & FNM_LEADING_DIR) ||
00101                                             strchr(string, '/') == NULL ?
00102                                             0 : FNM_NOMATCH);
00103                                 else
00104                                         return (0);
00105                         } else if (c == '/' && flags & FNM_PATHNAME) {
00106                                 if ((string = strchr(string, '/')) == NULL)
00107                                         return (FNM_NOMATCH);
00108                                 break;
00109                         }
00110 
00111                         /* General case, use recursion. */
00112                         while ((test = FOLDCASE(*string, flags)) != EOS) {
00113                                 if (!fnmatch(pattern, string,
00114                                              flags & ~FNM_PERIOD))
00115                                         return (0);
00116                                 if (test == '/' && flags & FNM_PATHNAME)
00117                                         break;
00118                                 ++string;
00119                         }
00120                         return (FNM_NOMATCH);
00121                 case '[':
00122                         if (*string == EOS)
00123                                 return (FNM_NOMATCH);
00124                         if (*string == '/' && flags & FNM_PATHNAME)
00125                                 return (FNM_NOMATCH);
00126                         if ((pattern =
00127                             rangematch(pattern, FOLDCASE(*string, flags),
00128                                        flags)) == NULL)
00129                                 return (FNM_NOMATCH);
00130                         ++string;
00131                         break;
00132                 case '\\':
00133                         if (!(flags & FNM_NOESCAPE)) {
00134                                 if ((c = FOLDCASE(*pattern++, flags)) == EOS) {
00135                                         c = '\\';
00136                                         --pattern;
00137                                 }
00138                         }
00139                         /* FALLTHROUGH */
00140                 default:
00141                         if (c != FOLDCASE(*string++, flags))
00142                                 return (FNM_NOMATCH);
00143                         break;
00144                 }
00145         /* NOTREACHED */
00146 }
00147 
00148 static const char *
00149 rangematch(pattern, test, flags)
00150         const char *pattern;
00151         int test, flags;
00152 {
00153         int negate, ok;
00154         char c, c2;
00155 
00156         /*
00157          * A bracket expression starting with an unquoted circumflex
00158          * character produces unspecified results (IEEE 1003.2-1992,
00159          * 3.13.2).  This implementation treats it like '!', for
00160          * consistency with the regular expression syntax.
00161          * J.T. Conklin (conklin@ngai.kaleida.com)
00162          */
00163         if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
00164                 ++pattern;
00165         
00166         for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) {
00167                 if (c == '\\' && !(flags & FNM_NOESCAPE))
00168                         c = FOLDCASE(*pattern++, flags);
00169                 if (c == EOS)
00170                         return (NULL);
00171                 if (*pattern == '-' 
00172                     && (c2 = FOLDCASE(*(pattern+1), flags)) != EOS &&
00173                         c2 != ']') {
00174                         pattern += 2;
00175                         if (c2 == '\\' && !(flags & FNM_NOESCAPE))
00176                                 c2 = FOLDCASE(*pattern++, flags);
00177                         if (c2 == EOS)
00178                                 return (NULL);
00179                         if (c <= test && test <= c2)
00180                                 ok = 1;
00181                 } else if (c == test)
00182                         ok = 1;
00183         }
00184         return (ok == negate ? NULL : pattern);
00185 }

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