Home | History | Annotate | Line # | Download | only in gen
      1  1.26  christos /*	$NetBSD: fnmatch.c,v 1.26 2014/10/12 22:32:33 christos Exp $	*/
      2  1.11       cgd 
      3   1.1       cgd /*
      4  1.11       cgd  * Copyright (c) 1989, 1993, 1994
      5   1.6       cgd  *	The Regents of the University of California.  All rights reserved.
      6   1.1       cgd  *
      7   1.1       cgd  * This code is derived from software contributed to Berkeley by
      8   1.1       cgd  * Guido van Rossum.
      9   1.1       cgd  *
     10   1.1       cgd  * Redistribution and use in source and binary forms, with or without
     11   1.1       cgd  * modification, are permitted provided that the following conditions
     12   1.1       cgd  * are met:
     13   1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     14   1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     15   1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     17   1.1       cgd  *    documentation and/or other materials provided with the distribution.
     18  1.20       agc  * 3. Neither the name of the University nor the names of its contributors
     19   1.1       cgd  *    may be used to endorse or promote products derived from this software
     20   1.1       cgd  *    without specific prior written permission.
     21   1.1       cgd  *
     22   1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23   1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24   1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25   1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26   1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27   1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28   1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29   1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30   1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31   1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32   1.1       cgd  * SUCH DAMAGE.
     33   1.1       cgd  */
     34   1.1       cgd 
     35  1.12  christos #include <sys/cdefs.h>
     36   1.1       cgd #if defined(LIBC_SCCS) && !defined(lint)
     37  1.11       cgd #if 0
     38  1.11       cgd static char sccsid[] = "@(#)fnmatch.c	8.2 (Berkeley) 4/16/94";
     39  1.11       cgd #else
     40  1.26  christos __RCSID("$NetBSD: fnmatch.c,v 1.26 2014/10/12 22:32:33 christos Exp $");
     41  1.11       cgd #endif
     42   1.1       cgd #endif /* LIBC_SCCS and not lint */
     43   1.1       cgd 
     44   1.1       cgd /*
     45   1.7       jtc  * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
     46   1.1       cgd  * Compares a filename or pathname to a pattern.
     47   1.1       cgd  */
     48   1.1       cgd 
     49  1.13       jtc #include "namespace.h"
     50  1.15     lukem 
     51  1.15     lukem #include <assert.h>
     52  1.18   thorpej #include <ctype.h>
     53   1.3       jtc #include <fnmatch.h>
     54   1.1       cgd #include <string.h>
     55  1.13       jtc 
     56  1.13       jtc #ifdef __weak_alias
     57  1.17   mycroft __weak_alias(fnmatch,_fnmatch)
     58  1.13       jtc #endif
     59   1.1       cgd 
     60   1.1       cgd #define	EOS	'\0'
     61   1.1       cgd 
     62  1.21     perry static inline int
     63  1.18   thorpej foldcase(int ch, int flags)
     64  1.18   thorpej {
     65  1.18   thorpej 
     66  1.18   thorpej 	if ((flags & FNM_CASEFOLD) != 0 && isupper(ch))
     67  1.22  christos 		return tolower(ch);
     68  1.22  christos 	return ch;
     69  1.18   thorpej }
     70  1.18   thorpej 
     71  1.18   thorpej #define	FOLDCASE(ch, flags)	foldcase((unsigned char)(ch), (flags))
     72  1.18   thorpej 
     73  1.22  christos static const char *
     74  1.22  christos rangematch(const char *pattern, int test, int flags)
     75  1.22  christos {
     76  1.26  christos 	int negate, ok, need;
     77  1.22  christos 	char c, c2;
     78  1.22  christos 
     79  1.22  christos 	_DIAGASSERT(pattern != NULL);
     80  1.22  christos 
     81  1.22  christos 	/*
     82  1.22  christos 	 * A bracket expression starting with an unquoted circumflex
     83  1.22  christos 	 * character produces unspecified results (IEEE 1003.2-1992,
     84  1.22  christos 	 * 3.13.2).  This implementation treats it like '!', for
     85  1.22  christos 	 * consistency with the regular expression syntax.
     86  1.22  christos 	 * J.T. Conklin (conklin (at) ngai.kaleida.com)
     87  1.22  christos 	 */
     88  1.22  christos 	if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
     89  1.22  christos 		++pattern;
     90  1.22  christos 
     91  1.26  christos 	need = 1;
     92  1.26  christos 	for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']' || need;) {
     93  1.26  christos 		need = 0;
     94  1.26  christos 		if (c == '/')
     95  1.26  christos 			return (void *)-1;
     96  1.22  christos 		if (c == '\\' && !(flags & FNM_NOESCAPE))
     97  1.22  christos 			c = FOLDCASE(*pattern++, flags);
     98  1.22  christos 		if (c == EOS)
     99  1.22  christos 			return NULL;
    100  1.22  christos 		if (*pattern == '-'
    101  1.22  christos 		    && (c2 = FOLDCASE(*(pattern + 1), flags)) != EOS &&
    102  1.22  christos 		        c2 != ']') {
    103  1.22  christos 			pattern += 2;
    104  1.22  christos 			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
    105  1.22  christos 				c2 = FOLDCASE(*pattern++, flags);
    106  1.22  christos 			if (c2 == EOS)
    107  1.22  christos 				return NULL;
    108  1.22  christos 			if (c <= test && test <= c2)
    109  1.22  christos 				ok = 1;
    110  1.22  christos 		} else if (c == test)
    111  1.22  christos 			ok = 1;
    112  1.22  christos 	}
    113  1.22  christos 	return ok == negate ? NULL : pattern;
    114  1.22  christos }
    115  1.22  christos 
    116  1.22  christos 
    117  1.22  christos static int
    118  1.22  christos fnmatchx(const char *pattern, const char *string, int flags, size_t recursion)
    119   1.1       cgd {
    120  1.26  christos 	const char *stringstart, *r;
    121  1.11       cgd 	char c, test;
    122   1.1       cgd 
    123  1.15     lukem 	_DIAGASSERT(pattern != NULL);
    124  1.15     lukem 	_DIAGASSERT(string != NULL);
    125  1.15     lukem 
    126  1.22  christos 	if (recursion-- == 0)
    127  1.22  christos 		return FNM_NORES;
    128  1.22  christos 
    129  1.24  christos 	for (stringstart = string;;) {
    130  1.18   thorpej 		switch (c = FOLDCASE(*pattern++, flags)) {
    131   1.1       cgd 		case EOS:
    132  1.19    provos 			if ((flags & FNM_LEADING_DIR) && *string == '/')
    133  1.22  christos 				return 0;
    134  1.22  christos 			return *string == EOS ? 0 : FNM_NOMATCH;
    135   1.1       cgd 		case '?':
    136   1.8       jtc 			if (*string == EOS)
    137  1.22  christos 				return FNM_NOMATCH;
    138   1.8       jtc 			if (*string == '/' && (flags & FNM_PATHNAME))
    139  1.22  christos 				return FNM_NOMATCH;
    140   1.8       jtc 			if (*string == '.' && (flags & FNM_PERIOD) &&
    141  1.11       cgd 			    (string == stringstart ||
    142  1.11       cgd 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
    143  1.22  christos 				return FNM_NOMATCH;
    144   1.8       jtc 			++string;
    145   1.1       cgd 			break;
    146   1.1       cgd 		case '*':
    147  1.18   thorpej 			c = FOLDCASE(*pattern, flags);
    148   1.3       jtc 			/* Collapse multiple stars. */
    149   1.1       cgd 			while (c == '*')
    150  1.18   thorpej 				c = FOLDCASE(*++pattern, flags);
    151   1.1       cgd 
    152   1.8       jtc 			if (*string == '.' && (flags & FNM_PERIOD) &&
    153  1.11       cgd 			    (string == stringstart ||
    154  1.11       cgd 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
    155  1.22  christos 				return FNM_NOMATCH;
    156   1.8       jtc 
    157   1.3       jtc 			/* Optimize for pattern with * at end or before /. */
    158  1.14  christos 			if (c == EOS) {
    159   1.1       cgd 				if (flags & FNM_PATHNAME)
    160  1.22  christos 					return (flags & FNM_LEADING_DIR) ||
    161  1.19    provos 					    strchr(string, '/') == NULL ?
    162  1.22  christos 					    0 : FNM_NOMATCH;
    163   1.1       cgd 				else
    164  1.22  christos 					return 0;
    165  1.14  christos 			} else if (c == '/' && flags & FNM_PATHNAME) {
    166  1.10       jtc 				if ((string = strchr(string, '/')) == NULL)
    167  1.22  christos 					return FNM_NOMATCH;
    168   1.1       cgd 				break;
    169   1.1       cgd 			}
    170   1.1       cgd 
    171   1.3       jtc 			/* General case, use recursion. */
    172  1.18   thorpej 			while ((test = FOLDCASE(*string, flags)) != EOS) {
    173  1.22  christos 				int e;
    174  1.22  christos 				switch ((e = fnmatchx(pattern, string,
    175  1.22  christos 				    flags & ~FNM_PERIOD, recursion))) {
    176  1.22  christos 				case FNM_NOMATCH:
    177  1.22  christos 					break;
    178  1.22  christos 				default:
    179  1.22  christos 					return e;
    180  1.22  christos 				}
    181   1.1       cgd 				if (test == '/' && flags & FNM_PATHNAME)
    182   1.1       cgd 					break;
    183   1.1       cgd 				++string;
    184   1.1       cgd 			}
    185  1.22  christos 			return FNM_NOMATCH;
    186   1.1       cgd 		case '[':
    187   1.8       jtc 			if (*string == EOS)
    188  1.22  christos 				return FNM_NOMATCH;
    189   1.8       jtc 			if (*string == '/' && flags & FNM_PATHNAME)
    190  1.22  christos 				return FNM_NOMATCH;
    191  1.26  christos 			if ((r = rangematch(pattern,
    192  1.22  christos 			    FOLDCASE(*string, flags), flags)) == NULL)
    193  1.22  christos 				return FNM_NOMATCH;
    194  1.26  christos 			if (r == (void *)-1) {
    195  1.26  christos 				if (*string != '[')
    196  1.26  christos 					return FNM_NOMATCH;
    197  1.26  christos 			} else
    198  1.26  christos 				pattern = r;
    199   1.8       jtc 			++string;
    200   1.1       cgd 			break;
    201   1.1       cgd 		case '\\':
    202   1.3       jtc 			if (!(flags & FNM_NOESCAPE)) {
    203  1.18   thorpej 				if ((c = FOLDCASE(*pattern++, flags)) == EOS) {
    204  1.25  christos 					c = '\0';
    205   1.1       cgd 					--pattern;
    206   1.1       cgd 				}
    207   1.1       cgd 			}
    208   1.1       cgd 			/* FALLTHROUGH */
    209   1.1       cgd 		default:
    210  1.18   thorpej 			if (c != FOLDCASE(*string++, flags))
    211  1.22  christos 				return FNM_NOMATCH;
    212   1.1       cgd 			break;
    213   1.1       cgd 		}
    214  1.24  christos 	}
    215   1.3       jtc 	/* NOTREACHED */
    216   1.3       jtc }
    217   1.3       jtc 
    218  1.22  christos int
    219  1.22  christos fnmatch(const char *pattern, const char *string, int flags)
    220   1.3       jtc {
    221  1.23  christos 	return fnmatchx(pattern, string, flags, 64);
    222   1.1       cgd }
    223