1 /*	$NetBSD: fnmatch.c,v 1.1.1.1 2011/04/13 18:15:41 elric Exp $	*/
2 
3 /*	NetBSD: fnmatch.c,v 1.11 1995/02/27 03:43:06 cgd Exp	*/
4 
5 /*
6  * Copyright (c) 1989, 1993, 1994
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Guido van Rossum.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #if defined(LIBC_SCCS) && !defined(lint)
38 #if 0
39 static char sccsid[] = "@(#)fnmatch.c	8.2 (Berkeley) 4/16/94";
40 #else
41 static char rcsid[] = "NetBSD: fnmatch.c,v 1.11 1995/02/27 03:43:06 cgd Exp";
42 #endif
43 #endif /* LIBC_SCCS and not lint */
44 
45 /*
46  * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
47  * Compares a filename or pathname to a pattern.
48  */
49 
50 #ifdef HAVE_CONFIG_H
51 #include <config.h>
52 #endif
53 
54 #include <krb5/roken.h>
55 
56 #include <fnmatch.h>
57 #include <string.h>
58 
59 #define	EOS	'\0'
60 
61 static const char *rangematch (const char *, int, int);
62 
63 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
64 rk_fnmatch(const char *pattern, const char *string, int flags)
65 {
66 	const char *stringstart;
67 	char c, test;
68 
69 	for (stringstart = string;;)
70 		switch (c = *pattern++) {
71 		case EOS:
72 			return (*string == EOS ? 0 : FNM_NOMATCH);
73 		case '?':
74 			if (*string == EOS)
75 				return (FNM_NOMATCH);
76 			if (*string == '/' && (flags & FNM_PATHNAME))
77 				return (FNM_NOMATCH);
78 			if (*string == '.' && (flags & FNM_PERIOD) &&
79 			    (string == stringstart ||
80 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
81 				return (FNM_NOMATCH);
82 			++string;
83 			break;
84 		case '*':
85 			c = *pattern;
86 			/* Collapse multiple stars. */
87 			while (c == '*')
88 				c = *++pattern;
89 
90 			if (*string == '.' && (flags & FNM_PERIOD) &&
91 			    (string == stringstart ||
92 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
93 				return (FNM_NOMATCH);
94 
95 			/* Optimize for pattern with * at end or before /. */
96 			if (c == EOS)
97 				if (flags & FNM_PATHNAME)
98 					return (strchr(string, '/') == NULL ?
99 					    0 : FNM_NOMATCH);
100 				else
101 					return (0);
102 			else if (c == '/' && flags & FNM_PATHNAME) {
103 				if ((string = strchr(string, '/')) == NULL)
104 					return (FNM_NOMATCH);
105 				break;
106 			}
107 
108 			/* General case, use recursion. */
109 			while ((test = *string) != EOS) {
110 				if (!rk_fnmatch(pattern, string, flags & ~FNM_PERIOD))
111 					return (0);
112 				if (test == '/' && flags & FNM_PATHNAME)
113 					break;
114 				++string;
115 			}
116 			return (FNM_NOMATCH);
117 		case '[':
118 			if (*string == EOS)
119 				return (FNM_NOMATCH);
120 			if (*string == '/' && flags & FNM_PATHNAME)
121 				return (FNM_NOMATCH);
122 			if ((pattern =
123 			    rangematch(pattern, *string, flags)) == NULL)
124 				return (FNM_NOMATCH);
125 			++string;
126 			break;
127 		case '\\':
128 			if (!(flags & FNM_NOESCAPE)) {
129 				if ((c = *pattern++) == EOS) {
130 					c = '\\';
131 					--pattern;
132 				}
133 			}
134 			/* FALLTHROUGH */
135 		default:
136 			if (c != *string++)
137 				return (FNM_NOMATCH);
138 			break;
139 		}
140 	/* NOTREACHED */
141 }
142 
143 static const char *
144 rangematch(const char *pattern, int test, int flags)
145 {
146 	int negate, ok;
147 	char c, c2;
148 
149 	/*
150 	 * A bracket expression starting with an unquoted circumflex
151 	 * character produces unspecified results (IEEE 1003.2-1992,
152 	 * 3.13.2).  This implementation treats it like '!', for
153 	 * consistency with the regular expression syntax.
154 	 * J.T. Conklin (conklin@ngai.kaleida.com)
155 	 */
156 	if (negate = (*pattern == '!' || *pattern == '^'))
157 		++pattern;
158 
159 	for (ok = 0; (c = *pattern++) != ']';) {
160 		if (c == '\\' && !(flags & FNM_NOESCAPE))
161 			c = *pattern++;
162 		if (c == EOS)
163 			return (NULL);
164 		if (*pattern == '-'
165 		    && (c2 = *(pattern+1)) != EOS && c2 != ']') {
166 			pattern += 2;
167 			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
168 				c2 = *pattern++;
169 			if (c2 == EOS)
170 				return (NULL);
171 			if (c <= test && test <= c2)
172 				ok = 1;
173 		} else if (c == test)
174 			ok = 1;
175 	}
176 	return (ok == negate ? NULL : pattern);
177 }
178