xref: /dpdk/lib/eal/windows/include/fnmatch.h (revision 1fcd0b17993579c717976fc2e502c1b236b87fba)
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 #ifndef _FNMATCH_H_
9 #define _FNMATCH_H_
10 
11 /*
12  * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
13  * Compares a filename or pathname to a pattern.
14  */
15 
16 #include <ctype.h>
17 #include <string.h>
18 #include <stdio.h>
19 
20 #define FNM_NOMATCH 1
21 
22 #define FNM_NOESCAPE 0x01
23 #define FNM_PATHNAME 0x02
24 #define FNM_PERIOD 0x04
25 #define FNM_LEADING_DIR 0x08
26 #define FNM_CASEFOLD 0x10
27 #define FNM_PREFIX_DIRS 0x20
28 
29 #define FNM_EOS	'\0'
30 
31 static inline const char *
fnm_rangematch(const char * pattern,char test,int flags)32 fnm_rangematch(const char *pattern, char test, int flags)
33 {
34 	int negate, ok;
35 	char c, c2;
36 
37 	/*
38 	 * A bracket expression starting with an unquoted circumflex
39 	 * character produces unspecified results (IEEE 1003.2-1992,
40 	 * 3.13.2).  This implementation treats it like '!', for
41 	 * consistency with the regular expression syntax.
42 	 * J.T. Conklin (conklin@ngai.kaleida.com)
43 	 */
44 	negate = (*pattern == '!' || *pattern == '^');
45 	if (negate)
46 		++pattern;
47 
48 	if (flags & FNM_CASEFOLD)
49 		test = tolower((unsigned char)test);
50 
51 	for (ok = 0; (c = *pattern++) != ']';) {
52 		if (c == '\\' && !(flags & FNM_NOESCAPE))
53 			c = *pattern++;
54 		if (c == FNM_EOS)
55 			return (NULL);
56 
57 		if (flags & FNM_CASEFOLD)
58 			c = tolower((unsigned char)c);
59 
60 		c2 = *(pattern + 1);
61 		if (*pattern == '-' && c2 != FNM_EOS && c2 != ']') {
62 			pattern += 2;
63 			if (c2 == '\\' && !(flags & FNM_NOESCAPE))
64 				c2 = *pattern++;
65 			if (c2 == FNM_EOS)
66 				return (NULL);
67 
68 			if (flags & FNM_CASEFOLD)
69 				c2 = tolower((unsigned char)c2);
70 
71 			if ((unsigned char)c <= (unsigned char)test &&
72 			    (unsigned char)test <= (unsigned char)c2)
73 				ok = 1;
74 		} else if (c == test)
75 			ok = 1;
76 	}
77 	return (ok == negate ? NULL : pattern);
78 }
79 
80 /**
81  * This function is used for searching a given string source
82  * with the given regular expression pattern.
83  *
84  * @param pattern
85  *	regular expression notation describing the pattern to match
86  *
87  * @param string
88  *	source string to search for the pattern
89  *
90  * @param flag
91  *	containing information about the pattern
92  *
93  * @return
94  *	if the pattern is found then return 0 or else FNM_NOMATCH
95  */
96 static inline int
fnmatch(const char * pattern,const char * string,int flags)97 fnmatch(const char *pattern, const char *string, int flags)
98 {
99 	const char *stringstart;
100 	char c, test;
101 
102 	for (stringstart = string;;)
103 		switch (c = *pattern++) {
104 		case FNM_EOS:
105 			if ((flags & FNM_LEADING_DIR) && *string == '/')
106 				return (0);
107 			return (*string == FNM_EOS ? 0 : FNM_NOMATCH);
108 		case '?':
109 			if (*string == FNM_EOS)
110 				return (FNM_NOMATCH);
111 			if (*string == '/' && (flags & FNM_PATHNAME))
112 				return (FNM_NOMATCH);
113 			if (*string == '.' && (flags & FNM_PERIOD) &&
114 			    (string == stringstart ||
115 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
116 				return (FNM_NOMATCH);
117 			++string;
118 			break;
119 		case '*':
120 			c = *pattern;
121 			/* Collapse multiple stars. */
122 			while (c == '*')
123 				c = *++pattern;
124 
125 			if (*string == '.' && (flags & FNM_PERIOD) &&
126 			    (string == stringstart ||
127 			    ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
128 				return (FNM_NOMATCH);
129 
130 			/* Optimize for pattern with * at end or before /. */
131 			if (c == FNM_EOS)
132 				if (flags & FNM_PATHNAME)
133 					return ((flags & FNM_LEADING_DIR) ||
134 					    strchr(string, '/') == NULL ?
135 					    0 : FNM_NOMATCH);
136 				else
137 					return (0);
138 			else if (c == '/' && flags & FNM_PATHNAME) {
139 				string = strchr(string, '/');
140 				if (string == NULL)
141 					return (FNM_NOMATCH);
142 				break;
143 			}
144 
145 			/* General case, use recursion. */
146 			while ((test = *string) != FNM_EOS) {
147 				if (!fnmatch(pattern, string,
148 					flags & ~FNM_PERIOD))
149 					return (0);
150 				if (test == '/' && flags & FNM_PATHNAME)
151 					break;
152 				++string;
153 			}
154 			return (FNM_NOMATCH);
155 		case '[':
156 			if (*string == FNM_EOS)
157 				return (FNM_NOMATCH);
158 			if (*string == '/' && flags & FNM_PATHNAME)
159 				return (FNM_NOMATCH);
160 			pattern = fnm_rangematch(pattern, *string, flags);
161 			if (pattern == NULL)
162 				return (FNM_NOMATCH);
163 			++string;
164 			break;
165 		case '\\':
166 			if (!(flags & FNM_NOESCAPE)) {
167 				c = *pattern++;
168 				if (c == FNM_EOS) {
169 					c = '\\';
170 					--pattern;
171 				}
172 			}
173 			/* FALLTHROUGH */
174 		default:
175 			if (c == *string)
176 				;
177 			else if ((flags & FNM_CASEFOLD) &&
178 				 (tolower((unsigned char)c) ==
179 				  tolower((unsigned char)*string)))
180 				;
181 			else if ((flags & FNM_PREFIX_DIRS) && *string == FNM_EOS &&
182 			     ((c == '/' && string != stringstart) ||
183 			     (string == stringstart+1 && *stringstart == '/')))
184 				return (0);
185 			else
186 				return (FNM_NOMATCH);
187 			string++;
188 			break;
189 		}
190 	/* NOTREACHED */
191 }
192 
193 #endif /* _FNMATCH_H_ */
194