xref: /dpdk/lib/eal/windows/fnmatch.c (revision 99a2dd95)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 1989, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Guido van Rossum.
7  */
8 
9 #if defined(LIBC_SCCS) && !defined(lint)
10 static const char sccsid[] = "@(#)fnmatch.c	8.2 (Berkeley) 4/16/94";
11 #endif /* LIBC_SCCS and not lint */
12 
13 /*
14  * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
15  * Compares a filename or pathname to a pattern.
16  */
17 
18 #include <ctype.h>
19 #include <string.h>
20 #include <stdio.h>
21 
22 #include "fnmatch.h"
23 
24 #define EOS	'\0'
25 
26 static const char *rangematch(const char *, char, int);
27 
28 int
fnmatch(const char * pattern,const char * string,int flags)29 fnmatch(const char *pattern, const char *string, int flags)
30 {
31 	const char *stringstart;
32 	char c, test;
33 
34 	for (stringstart = string;;)
35 		switch (c = *pattern++) {
36 		case EOS:
37 			if ((flags & FNM_LEADING_DIR) && *string == '/')
38 				return (0);
39 			return (*string == EOS ? 0 : FNM_NOMATCH);
40 		case '?':
41 			if (*string == EOS)
42 				return (FNM_NOMATCH);
43 			if (*string == '/' && (flags & FNM_PATHNAME))
44 				return (FNM_NOMATCH);
45 			if (*string == '.' && (flags & FNM_PERIOD) &&
46 			    (string == stringstart ||
47 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
48 				return (FNM_NOMATCH);
49 			++string;
50 			break;
51 		case '*':
52 			c = *pattern;
53 			/* Collapse multiple stars. */
54 			while (c == '*')
55 				c = *++pattern;
56 
57 			if (*string == '.' && (flags & FNM_PERIOD) &&
58 			    (string == stringstart ||
59 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
60 				return (FNM_NOMATCH);
61 
62 			/* Optimize for pattern with * at end or before /. */
63 			if (c == EOS)
64 				if (flags & FNM_PATHNAME)
65 					return ((flags & FNM_LEADING_DIR) ||
66 					    strchr(string, '/') == NULL ?
67 					    0 : FNM_NOMATCH);
68 				else
69 					return (0);
70 			else if (c == '/' && flags & FNM_PATHNAME) {
71 				string = strchr(string, '/');
72 				if (string == NULL)
73 					return (FNM_NOMATCH);
74 				break;
75 			}
76 
77 			/* General case, use recursion. */
78 			while ((test = *string) != EOS) {
79 				if (!fnmatch(pattern, string,
80 					flags & ~FNM_PERIOD))
81 					return (0);
82 				if (test == '/' && flags & FNM_PATHNAME)
83 					break;
84 				++string;
85 			}
86 			return (FNM_NOMATCH);
87 		case '[':
88 			if (*string == EOS)
89 				return (FNM_NOMATCH);
90 			if (*string == '/' && flags & FNM_PATHNAME)
91 				return (FNM_NOMATCH);
92 			pattern = rangematch(pattern, *string, flags);
93 			if (pattern == NULL)
94 				return (FNM_NOMATCH);
95 			++string;
96 			break;
97 		case '\\':
98 			if (!(flags & FNM_NOESCAPE)) {
99 				c = *pattern++;
100 				if (c == EOS) {
101 					c = '\\';
102 					--pattern;
103 				}
104 			}
105 			/* FALLTHROUGH */
106 		default:
107 			if (c == *string)
108 				;
109 			else if ((flags & FNM_CASEFOLD) &&
110 				 (tolower((unsigned char)c) ==
111 				  tolower((unsigned char)*string)))
112 				;
113 			else if ((flags & FNM_PREFIX_DIRS) && *string == EOS &&
114 			     ((c == '/' && string != stringstart) ||
115 			     (string == stringstart+1 && *stringstart == '/')))
116 				return (0);
117 			else
118 				return (FNM_NOMATCH);
119 			string++;
120 			break;
121 		}
122 	/* NOTREACHED */
123 }
124 
125 static const char *
rangematch(const char * pattern,char test,int flags)126 rangematch(const char *pattern, char test, int flags)
127 {
128 	int negate, ok;
129 	char c, c2;
130 
131 	/*
132 	 * A bracket expression starting with an unquoted circumflex
133 	 * character produces unspecified results (IEEE 1003.2-1992,
134 	 * 3.13.2).  This implementation treats it like '!', for
135 	 * consistency with the regular expression syntax.
136 	 * J.T. Conklin ([email protected])
137 	 */
138 	negate = (*pattern == '!' || *pattern == '^');
139 	if (negate)
140 		++pattern;
141 
142 	if (flags & FNM_CASEFOLD)
143 		test = tolower((unsigned char)test);
144 
145 	for (ok = 0; (c = *pattern++) != ']';) {
146 		if (c == '\\' && !(flags & FNM_NOESCAPE))
147 			c = *pattern++;
148 		if (c == EOS)
149 			return (NULL);
150 
151 		if (flags & FNM_CASEFOLD)
152 			c = tolower((unsigned char)c);
153 
154 		c2 = *(pattern + 1);
155 		if (*pattern == '-' && c2 != EOS && c2 != ']') {
156 			pattern += 2;
157 			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
158 				c2 = *pattern++;
159 			if (c2 == EOS)
160 				return (NULL);
161 
162 			if (flags & FNM_CASEFOLD)
163 				c2 = tolower((unsigned char)c2);
164 
165 			if ((unsigned char)c <= (unsigned char)test &&
166 			    (unsigned char)test <= (unsigned char)c2)
167 				ok = 1;
168 		} else if (c == test)
169 			ok = 1;
170 	}
171 	return (ok == negate ? NULL : pattern);
172 }
173