Blame src/fnmatch.c

Packit Service 20376f
/*
Packit Service 20376f
 * Copyright (C) the libgit2 contributors. All rights reserved.
Packit Service 20376f
 *
Packit Service 20376f
 * This file is part of libgit2, distributed under the GNU GPL v2 with
Packit Service 20376f
 * a Linking Exception. For full terms see the included COPYING file.
Packit Service 20376f
 */
Packit Service 20376f
Packit Service 20376f
/*
Packit Service 20376f
 * This file contains code originally derrived from OpenBSD fnmatch.c 
Packit Service 20376f
 *
Packit Service 20376f
 * Copyright (c) 1989, 1993, 1994
Packit Service 20376f
 *      The Regents of the University of California.  All rights reserved.
Packit Service 20376f
 *
Packit Service 20376f
 * This code is derived from software contributed to Berkeley by
Packit Service 20376f
 * Guido van Rossum.
Packit Service 20376f
 *
Packit Service 20376f
 * Redistribution and use in source and binary forms, with or without
Packit Service 20376f
 * modification, are permitted provided that the following conditions
Packit Service 20376f
 * are met:
Packit Service 20376f
 * 1. Redistributions of source code must retain the above copyright
Packit Service 20376f
 *    notice, this list of conditions and the following disclaimer.
Packit Service 20376f
 * 2. Redistributions in binary form must reproduce the above copyright
Packit Service 20376f
 *    notice, this list of conditions and the following disclaimer in the
Packit Service 20376f
 *    documentation and/or other materials provided with the distribution.
Packit Service 20376f
 * 3. Neither the name of the University nor the names of its contributors
Packit Service 20376f
 *    may be used to endorse or promote products derived from this software
Packit Service 20376f
 *    without specific prior written permission.
Packit Service 20376f
 *
Packit Service 20376f
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
Packit Service 20376f
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit Service 20376f
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit Service 20376f
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
Packit Service 20376f
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit Service 20376f
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit Service 20376f
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit Service 20376f
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit Service 20376f
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit Service 20376f
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit Service 20376f
 * SUCH DAMAGE.
Packit Service 20376f
 */
Packit Service 20376f
Packit Service 20376f
/*
Packit Service 20376f
 * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
Packit Service 20376f
 * Compares a filename or pathname to a pattern.
Packit Service 20376f
 */
Packit Service 20376f
Packit Service 20376f
#include <ctype.h>
Packit Service 20376f
#include <stdio.h>
Packit Service 20376f
#include <string.h>
Packit Service 20376f
Packit Service 20376f
#include "fnmatch.h"
Packit Service 20376f
Packit Service 20376f
#define EOS		'\0'
Packit Service 20376f
Packit Service 20376f
#define RANGE_MATCH		1
Packit Service 20376f
#define RANGE_NOMATCH		0
Packit Service 20376f
#define RANGE_ERROR		(-1)
Packit Service 20376f
Packit Service 20376f
static int rangematch(const char *, char, int, char **);
Packit Service 20376f
Packit Service 20376f
static int
Packit Service 20376f
p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs)
Packit Service 20376f
{
Packit Service 20376f
		const char *stringstart;
Packit Service 20376f
		char *newp;
Packit Service 20376f
		char c, test;
Packit Service 20376f
		int recurs_flags = flags & ~FNM_PERIOD;
Packit Service 20376f
Packit Service 20376f
		if (recurs-- == 0)
Packit Service 20376f
				return FNM_NORES;
Packit Service 20376f
Packit Service 20376f
		for (stringstart = string;;)
Packit Service 20376f
				switch (c = *pattern++) {
Packit Service 20376f
				case EOS:
Packit Service 20376f
						if ((flags & FNM_LEADING_DIR) && *string == '/')
Packit Service 20376f
								return (0);
Packit Service 20376f
						return (*string == EOS ? 0 : FNM_NOMATCH);
Packit Service 20376f
				case '?':
Packit Service 20376f
						if (*string == EOS)
Packit Service 20376f
								return (FNM_NOMATCH);
Packit Service 20376f
						if (*string == '/' && (flags & FNM_PATHNAME))
Packit Service 20376f
								return (FNM_NOMATCH);
Packit Service 20376f
						if (*string == '.' && (flags & FNM_PERIOD) &&
Packit Service 20376f
							(string == stringstart ||
Packit Service 20376f
							((flags & FNM_PATHNAME) && *(string - 1) == '/')))
Packit Service 20376f
								return (FNM_NOMATCH);
Packit Service 20376f
						++string;
Packit Service 20376f
						break;
Packit Service 20376f
				case '*':
Packit Service 20376f
						c = *pattern;
Packit Service 20376f
Packit Service 20376f
						/* Let '**' override PATHNAME match for this segment.
Packit Service 20376f
						 * It will be restored if/when we recurse below.
Packit Service 20376f
						 */
Packit Service 20376f
						if (c == '*') {
Packit Service 20376f
							c = *++pattern;
Packit Service 20376f
							/* star-star-slash is at the end, match by default */
Packit Service 20376f
							if (c == EOS)
Packit Service 20376f
								return 0;
Packit Service 20376f
							/* Double-star must be at end or between slashes */
Packit Service 20376f
							if (c != '/')
Packit Service 20376f
								return (FNM_NOMATCH);
Packit Service 20376f
Packit Service 20376f
							c = *++pattern;
Packit Service 20376f
							do {
Packit Service 20376f
								int e = p_fnmatchx(pattern, string, recurs_flags, recurs);
Packit Service 20376f
								if (e != FNM_NOMATCH)
Packit Service 20376f
									return e;
Packit Service 20376f
								string = strchr(string, '/');
Packit Service 20376f
							} while (string++);
Packit Service 20376f
Packit Service 20376f
							/* If we get here, we didn't find a match */
Packit Service 20376f
							return FNM_NOMATCH;
Packit Service 20376f
						}
Packit Service 20376f
Packit Service 20376f
						if (*string == '.' && (flags & FNM_PERIOD) &&
Packit Service 20376f
							(string == stringstart ||
Packit Service 20376f
							((flags & FNM_PATHNAME) && *(string - 1) == '/')))
Packit Service 20376f
								return (FNM_NOMATCH);
Packit Service 20376f
Packit Service 20376f
						/* Optimize for pattern with * at end or before /. */
Packit Service 20376f
						if (c == EOS) {
Packit Service 20376f
								if (flags & FNM_PATHNAME)
Packit Service 20376f
										return ((flags & FNM_LEADING_DIR) ||
Packit Service 20376f
											strchr(string, '/') == NULL ?
Packit Service 20376f
											0 : FNM_NOMATCH);
Packit Service 20376f
								else
Packit Service 20376f
										return (0);
Packit Service 20376f
						} else if (c == '/' && (flags & FNM_PATHNAME)) {
Packit Service 20376f
								if ((string = strchr(string, '/')) == NULL)
Packit Service 20376f
										return (FNM_NOMATCH);
Packit Service 20376f
								break;
Packit Service 20376f
						}
Packit Service 20376f
Packit Service 20376f
						/* General case, use recursion. */
Packit Service 20376f
						while ((test = *string) != EOS) {
Packit Service 20376f
								int e;
Packit Service 20376f
Packit Service 20376f
								e = p_fnmatchx(pattern, string, recurs_flags, recurs);
Packit Service 20376f
								if (e != FNM_NOMATCH)
Packit Service 20376f
										return e;
Packit Service 20376f
								if (test == '/' && (flags & FNM_PATHNAME))
Packit Service 20376f
										break;
Packit Service 20376f
								++string;
Packit Service 20376f
						}
Packit Service 20376f
						return (FNM_NOMATCH);
Packit Service 20376f
				case '[':
Packit Service 20376f
						if (*string == EOS)
Packit Service 20376f
								return (FNM_NOMATCH);
Packit Service 20376f
						if (*string == '/' && (flags & FNM_PATHNAME))
Packit Service 20376f
								return (FNM_NOMATCH);
Packit Service 20376f
						if (*string == '.' && (flags & FNM_PERIOD) &&
Packit Service 20376f
							(string == stringstart ||
Packit Service 20376f
							((flags & FNM_PATHNAME) && *(string - 1) == '/')))
Packit Service 20376f
								return (FNM_NOMATCH);
Packit Service 20376f
Packit Service 20376f
						switch (rangematch(pattern, *string, flags, &newp)) {
Packit Service 20376f
						case RANGE_ERROR:
Packit Service 20376f
								/* not a good range, treat as normal text */
Packit Service 20376f
								goto normal;
Packit Service 20376f
						case RANGE_MATCH:
Packit Service 20376f
								pattern = newp;
Packit Service 20376f
								break;
Packit Service 20376f
						case RANGE_NOMATCH:
Packit Service 20376f
								return (FNM_NOMATCH);
Packit Service 20376f
						}
Packit Service 20376f
						++string;
Packit Service 20376f
						break;
Packit Service 20376f
				case '\\':
Packit Service 20376f
						if (!(flags & FNM_NOESCAPE)) {
Packit Service 20376f
								if ((c = *pattern++) == EOS) {
Packit Service 20376f
										c = '\\';
Packit Service 20376f
										--pattern;
Packit Service 20376f
								}
Packit Service 20376f
						}
Packit Service 20376f
						/* FALLTHROUGH */
Packit Service 20376f
				default:
Packit Service 20376f
				normal:
Packit Service 20376f
						if (c != *string && !((flags & FNM_CASEFOLD) &&
Packit Service 20376f
									(git__tolower((unsigned char)c) ==
Packit Service 20376f
									git__tolower((unsigned char)*string))))
Packit Service 20376f
								return (FNM_NOMATCH);
Packit Service 20376f
						++string;
Packit Service 20376f
						break;
Packit Service 20376f
				}
Packit Service 20376f
		/* NOTREACHED */
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static int
Packit Service 20376f
rangematch(const char *pattern, char test, int flags, char **newp)
Packit Service 20376f
{
Packit Service 20376f
		int negate, ok;
Packit Service 20376f
		char c, c2;
Packit Service 20376f
Packit Service 20376f
		/*
Packit Service 20376f
			* A bracket expression starting with an unquoted circumflex
Packit Service 20376f
			* character produces unspecified results (IEEE 1003.2-1992,
Packit Service 20376f
			* 3.13.2). This implementation treats it like '!', for
Packit Service 20376f
			* consistency with the regular expression syntax.
Packit Service 20376f
			* J.T. Conklin (conklin@ngai.kaleida.com)
Packit Service 20376f
			*/
Packit Service 20376f
		if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
Packit Service 20376f
				++pattern;
Packit Service 20376f
Packit Service 20376f
		if (flags & FNM_CASEFOLD)
Packit Service 20376f
				test = (char)git__tolower((unsigned char)test);
Packit Service 20376f
Packit Service 20376f
		/*
Packit Service 20376f
			* A right bracket shall lose its special meaning and represent
Packit Service 20376f
			* itself in a bracket expression if it occurs first in the list.
Packit Service 20376f
			* -- POSIX.2 2.8.3.2
Packit Service 20376f
			*/
Packit Service 20376f
		ok = 0;
Packit Service 20376f
		c = *pattern++;
Packit Service 20376f
		do {
Packit Service 20376f
				if (c == '\\' && !(flags & FNM_NOESCAPE))
Packit Service 20376f
						c = *pattern++;
Packit Service 20376f
				if (c == EOS)
Packit Service 20376f
						return (RANGE_ERROR);
Packit Service 20376f
				if (c == '/' && (flags & FNM_PATHNAME))
Packit Service 20376f
						return (RANGE_NOMATCH);
Packit Service 20376f
				if ((flags & FNM_CASEFOLD))
Packit Service 20376f
						c = (char)git__tolower((unsigned char)c);
Packit Service 20376f
				if (*pattern == '-'
Packit Service 20376f
					&& (c2 = *(pattern+1)) != EOS && c2 != ']') {
Packit Service 20376f
						pattern += 2;
Packit Service 20376f
						if (c2 == '\\' && !(flags & FNM_NOESCAPE))
Packit Service 20376f
								c2 = *pattern++;
Packit Service 20376f
						if (c2 == EOS)
Packit Service 20376f
								return (RANGE_ERROR);
Packit Service 20376f
						if (flags & FNM_CASEFOLD)
Packit Service 20376f
								c2 = (char)git__tolower((unsigned char)c2);
Packit Service 20376f
						if (c <= test && test <= c2)
Packit Service 20376f
								ok = 1;
Packit Service 20376f
				} else if (c == test)
Packit Service 20376f
						ok = 1;
Packit Service 20376f
		} while ((c = *pattern++) != ']');
Packit Service 20376f
Packit Service 20376f
		*newp = (char *)pattern;
Packit Service 20376f
		return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int
Packit Service 20376f
p_fnmatch(const char *pattern, const char *string, int flags)
Packit Service 20376f
{
Packit Service 20376f
		return p_fnmatchx(pattern, string, flags, 64);
Packit Service 20376f
}
Packit Service 20376f