/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1989, 1993, 19944* The Regents of the University of California. All rights reserved.5*6* This code is derived from software contributed to Berkeley by7* Guido van Rossum.8*9* Redistribution and use in source and binary forms, with or without10* modification, are permitted provided that the following conditions11* are met:12* 1. Redistributions of source code must retain the above copyright13* notice, this list of conditions and the following disclaimer.14* 2. Redistributions in binary form must reproduce the above copyright15* notice, this list of conditions and the following disclaimer in the16* documentation and/or other materials provided with the distribution.17* 3. Neither the name of the University nor the names of its contributors18* may be used to endorse or promote products derived from this software19* without specific prior written permission.20*21* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND22* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE23* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE24* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE25* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL26* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS27* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)28* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT29* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY30* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF31* SUCH DAMAGE.32*/3334#include <sys/cdefs.h>35/*36* Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.37* Compares a filename or pathname to a pattern.38*/3940#include <sys/param.h>41#include <sys/ctype.h>42#include <sys/libkern.h>4344#define EOS '\0'4546#define RANGE_MATCH 147#define RANGE_NOMATCH 048#define RANGE_ERROR (-1)4950static int rangematch(const char *, char, int, char **);5152int53fnmatch(const char *pattern, const char *string, int flags)54{55const char *stringstart;56char *newp;57char c, test;5859for (stringstart = string;;)60switch (c = *pattern++) {61case EOS:62if ((flags & FNM_LEADING_DIR) && *string == '/')63return (0);64return (*string == EOS ? 0 : FNM_NOMATCH);65case '?':66if (*string == EOS)67return (FNM_NOMATCH);68if (*string == '/' && (flags & FNM_PATHNAME))69return (FNM_NOMATCH);70if (*string == '.' && (flags & FNM_PERIOD) &&71(string == stringstart ||72((flags & FNM_PATHNAME) && *(string - 1) == '/')))73return (FNM_NOMATCH);74++string;75break;76case '*':77c = *pattern;78/* Collapse multiple stars. */79while (c == '*')80c = *++pattern;8182if (*string == '.' && (flags & FNM_PERIOD) &&83(string == stringstart ||84((flags & FNM_PATHNAME) && *(string - 1) == '/')))85return (FNM_NOMATCH);8687/* Optimize for pattern with * at end or before /. */88if (c == EOS)89if (flags & FNM_PATHNAME)90return ((flags & FNM_LEADING_DIR) ||91strchr(string, '/') == NULL ?920 : FNM_NOMATCH);93else94return (0);95else if (c == '/' && flags & FNM_PATHNAME) {96if ((string = strchr(string, '/')) == NULL)97return (FNM_NOMATCH);98break;99}100101/* General case, use recursion. */102while ((test = *string) != EOS) {103if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))104return (0);105if (test == '/' && flags & FNM_PATHNAME)106break;107++string;108}109return (FNM_NOMATCH);110case '[':111if (*string == EOS)112return (FNM_NOMATCH);113if (*string == '/' && (flags & FNM_PATHNAME))114return (FNM_NOMATCH);115if (*string == '.' && (flags & FNM_PERIOD) &&116(string == stringstart ||117((flags & FNM_PATHNAME) && *(string - 1) == '/')))118return (FNM_NOMATCH);119120switch (rangematch(pattern, *string, flags, &newp)) {121case RANGE_ERROR:122goto norm;123case RANGE_MATCH:124pattern = newp;125break;126case RANGE_NOMATCH:127return (FNM_NOMATCH);128}129++string;130break;131case '\\':132if (!(flags & FNM_NOESCAPE)) {133if ((c = *pattern++) == EOS) {134c = '\\';135--pattern;136}137}138/* FALLTHROUGH */139default:140norm:141if (c == *string)142;143else if ((flags & FNM_CASEFOLD) &&144(tolower((unsigned char)c) ==145tolower((unsigned char)*string)))146;147else148return (FNM_NOMATCH);149string++;150break;151}152/* NOTREACHED */153}154155static int156rangematch(const char *pattern, char test, int flags, char **newp)157{158int negate, ok;159char c, c2;160161/*162* A bracket expression starting with an unquoted circumflex163* character produces unspecified results (IEEE 1003.2-1992,164* 3.13.2). This implementation treats it like '!', for165* consistency with the regular expression syntax.166* J.T. Conklin ([email protected])167*/168if ( (negate = (*pattern == '!' || *pattern == '^')) )169++pattern;170171if (flags & FNM_CASEFOLD)172test = tolower((unsigned char)test);173174/*175* A right bracket shall lose its special meaning and represent176* itself in a bracket expression if it occurs first in the list.177* -- POSIX.2 2.8.3.2178*/179ok = 0;180c = *pattern++;181do {182if (c == '\\' && !(flags & FNM_NOESCAPE))183c = *pattern++;184if (c == EOS)185return (RANGE_ERROR);186187if (c == '/' && (flags & FNM_PATHNAME))188return (RANGE_NOMATCH);189190if (flags & FNM_CASEFOLD)191c = tolower((unsigned char)c);192193if (*pattern == '-'194&& (c2 = *(pattern+1)) != EOS && c2 != ']') {195pattern += 2;196if (c2 == '\\' && !(flags & FNM_NOESCAPE))197c2 = *pattern++;198if (c2 == EOS)199return (RANGE_ERROR);200201if (flags & FNM_CASEFOLD)202c2 = tolower((unsigned char)c2);203204if (c <= test && test <= c2)205ok = 1;206} else if (c == test)207ok = 1;208} while ((c = *pattern++) != ']');209210*newp = (char *)(uintptr_t)pattern;211return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);212}213214215