Back to index

php5  5.3.10
fnmatch.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1989, 1993, 1994
00003  *     The Regents of the University of California.  All rights reserved.
00004  *
00005  * This code is derived from software contributed to Berkeley by
00006  * Guido van Rossum.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. All advertising materials mentioning features or use of this software
00017  *    must display the following acknowledgement:
00018  *     This product includes software developed by the University of
00019  *     California, Berkeley and its contributors.
00020  * 4. Neither the name of the University nor the names of its contributors
00021  *    may be used to endorse or promote products derived from this software
00022  *    without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00025  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00027  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00028  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00030  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00031  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00033  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00034  * SUCH DAMAGE.
00035  *
00036  * From FreeBSD fnmatch.c 1.11
00037  * $Id: fnmatch.c 273994 2009-01-20 01:37:48Z pajoye $
00038  */
00039 
00040 #if defined(LIBC_SCCS) && !defined(lint)
00041 static char sccsid[] = "@(#)fnmatch.c     8.2 (Berkeley) 4/16/94";
00042 #endif /* LIBC_SCCS and not lint */
00043 
00044 /*
00045  * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
00046  * Compares a filename or pathname to a pattern.
00047  */
00048 
00049 #include <ctype.h>
00050 #include <string.h>
00051 #include <stdio.h>
00052 
00053 #include "fnmatch.h"
00054 
00055 #define       EOS    '\0'
00056 
00057 static const char *rangematch(const char *, char, int);
00058 
00059 PHPAPI 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 = *pattern++) {
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 = *pattern;
00083                      /* Collapse multiple stars. */
00084                      while (c == '*')
00085                             c = *++pattern;
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 = *string) != EOS) {
00108                             if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
00109                                    return (0);
00110                             if (test == '/' && flags & FNM_PATHNAME)
00111                                    break;
00112                             ++string;
00113                      }
00114                      return (FNM_NOMATCH);
00115               case '[':
00116                      if (*string == EOS)
00117                             return (FNM_NOMATCH);
00118                      if (*string == '/' && flags & FNM_PATHNAME)
00119                             return (FNM_NOMATCH);
00120                      if ((pattern =
00121                          rangematch(pattern, *string, flags)) == NULL)
00122                             return (FNM_NOMATCH);
00123                      ++string;
00124                      break;
00125               case '\\':
00126                      if (!(flags & FNM_NOESCAPE)) {
00127                             if ((c = *pattern++) == EOS) {
00128                                    c = '\\';
00129                                    --pattern;
00130                             }
00131                      }
00132                      /* FALLTHROUGH */
00133               default:
00134                      if (c == *string)
00135                             ;
00136                      else if ((flags & FNM_CASEFOLD) &&
00137                              (tolower((unsigned char)c) ==
00138                               tolower((unsigned char)*string)))
00139                             ;
00140                      else if ((flags & FNM_PREFIX_DIRS) && *string == EOS &&
00141                           (c == '/' && string != stringstart ||
00142                           string == stringstart+1 && *stringstart == '/') )
00143                             return (0);
00144                      else
00145                             return (FNM_NOMATCH);
00146                      string++;
00147                      break;
00148               }
00149        /* NOTREACHED */
00150 }
00151 
00152 static const char *
00153 rangematch(const char *pattern, char test, int flags)
00154 {
00155        int negate, ok;
00156        char c, c2;
00157 
00158        /*
00159         * A bracket expression starting with an unquoted circumflex
00160         * character produces unspecified results (IEEE 1003.2-1992,
00161         * 3.13.2).  This implementation treats it like '!', for
00162         * consistency with the regular expression syntax.
00163         * J.T. Conklin (conklin@ngai.kaleida.com)
00164         */
00165        if ( (negate = (*pattern == '!' || *pattern == '^')) )
00166               ++pattern;
00167 
00168        if (flags & FNM_CASEFOLD)
00169               test = tolower((unsigned char)test);
00170 
00171        for (ok = 0; (c = *pattern++) != ']';) {
00172               if (c == '\\' && !(flags & FNM_NOESCAPE))
00173                      c = *pattern++;
00174               if (c == EOS)
00175                      return (NULL);
00176 
00177               if (flags & FNM_CASEFOLD)
00178                      c = tolower((unsigned char)c);
00179 
00180               if (*pattern == '-'
00181                   && (c2 = *(pattern+1)) != EOS && c2 != ']') {
00182                      pattern += 2;
00183                      if (c2 == '\\' && !(flags & FNM_NOESCAPE))
00184                             c2 = *pattern++;
00185                      if (c2 == EOS)
00186                             return (NULL);
00187 
00188                      if (flags & FNM_CASEFOLD)
00189                             c2 = tolower((unsigned char)c2);
00190 
00191                      if ((unsigned char)c <= (unsigned char)test &&
00192                          (unsigned char)test <= (unsigned char)c2)
00193                             ok = 1;
00194               } else if (c == test)
00195                      ok = 1;
00196        }
00197        return (ok == negate ? NULL : pattern);
00198 }