summaryrefslogtreecommitdiff
path: root/openbsd-compat
diff options
context:
space:
mode:
Diffstat (limited to 'openbsd-compat')
-rw-r--r--openbsd-compat/bsd-cygwin_util.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/openbsd-compat/bsd-cygwin_util.c b/openbsd-compat/bsd-cygwin_util.c
index fb49e30f5..f721fca9d 100644
--- a/openbsd-compat/bsd-cygwin_util.c
+++ b/openbsd-compat/bsd-cygwin_util.c
@@ -37,6 +37,8 @@
37#include <string.h> 37#include <string.h>
38#include <unistd.h> 38#include <unistd.h>
39#include <stdarg.h> 39#include <stdarg.h>
40#include <wchar.h>
41#include <wctype.h>
40 42
41#include "xmalloc.h" 43#include "xmalloc.h"
42 44
@@ -117,4 +119,148 @@ free_windows_environment(char **p)
117 free(p); 119 free(p);
118} 120}
119 121
122/*
123 * Returns true if the given string matches the pattern (which may contain ?
124 * and * as wildcards), and zero if it does not match.
125 *
126 * The Cygwin version of this function must be case-insensitive and take
127 * Unicode characters into account.
128 */
129
130static int
131__match_pattern (const wchar_t *s, const wchar_t *pattern, int caseinsensitive)
132{
133 for (;;) {
134 /* If at end of pattern, accept if also at end of string. */
135 if (!*pattern)
136 return !*s;
137
138 if (*pattern == '*') {
139 /* Skip the asterisk. */
140 pattern++;
141
142 /* If at end of pattern, accept immediately. */
143 if (!*pattern)
144 return 1;
145
146 /* If next character in pattern is known, optimize. */
147 if (*pattern != '?' && *pattern != '*') {
148 /*
149 * Look instances of the next character in
150 * pattern, and try to match starting from
151 * those.
152 */
153 for (; *s; s++)
154 if (*s == *pattern &&
155 __match_pattern(s + 1, pattern + 1,
156 caseinsensitive))
157 return 1;
158 /* Failed. */
159 return 0;
160 }
161 /*
162 * Move ahead one character at a time and try to
163 * match at each position.
164 */
165 for (; *s; s++)
166 if (__match_pattern(s, pattern, caseinsensitive))
167 return 1;
168 /* Failed. */
169 return 0;
170 }
171 /*
172 * There must be at least one more character in the string.
173 * If we are at the end, fail.
174 */
175 if (!*s)
176 return 0;
177
178 /* Check if the next character of the string is acceptable. */
179 if (*pattern != '?' && (*pattern != *s &&
180 (!caseinsensitive || towlower(*pattern) != towlower(*s))))
181 return 0;
182
183 /* Move to the next character, both in string and in pattern. */
184 s++;
185 pattern++;
186 }
187 /* NOTREACHED */
188}
189
190static int
191_match_pattern(const char *s, const char *pattern, int caseinsensitive)
192{
193 wchar_t *ws;
194 wchar_t *wpattern;
195 size_t len;
196
197 if ((len = mbstowcs(NULL, s, 0)) < 0)
198 return 0;
199 ws = (wchar_t *) alloca((len + 1) * sizeof (wchar_t));
200 mbstowcs(ws, s, len + 1);
201 if ((len = mbstowcs(NULL, pattern, 0)) < 0)
202 return 0;
203 wpattern = (wchar_t *) alloca((len + 1) * sizeof (wchar_t));
204 mbstowcs(wpattern, pattern, len + 1);
205 return __match_pattern (ws, wpattern, caseinsensitive);
206}
207
208/*
209 * Tries to match the string against the
210 * comma-separated sequence of subpatterns (each possibly preceded by ! to
211 * indicate negation). Returns -1 if negation matches, 1 if there is
212 * a positive match, 0 if there is no match at all.
213 */
214int
215match_pattern_list(const char *string, const char *pattern, int caseinsensitive)
216{
217 char sub[1024];
218 int negated;
219 int got_positive;
220 u_int i, subi, len = strlen(pattern);
221
222 got_positive = 0;
223 for (i = 0; i < len;) {
224 /* Check if the subpattern is negated. */
225 if (pattern[i] == '!') {
226 negated = 1;
227 i++;
228 } else
229 negated = 0;
230
231 /*
232 * Extract the subpattern up to a comma or end. Convert the
233 * subpattern to lowercase.
234 */
235 for (subi = 0;
236 i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
237 subi++, i++)
238 sub[subi] = pattern[i];
239 /* If subpattern too long, return failure (no match). */
240 if (subi >= sizeof(sub) - 1)
241 return 0;
242
243 /* If the subpattern was terminated by a comma, then skip it. */
244 if (i < len && pattern[i] == ',')
245 i++;
246
247 /* Null-terminate the subpattern. */
248 sub[subi] = '\0';
249
250 /* Try to match the subpattern against the string. */
251 if (_match_pattern(string, sub, caseinsensitive)) {
252 if (negated)
253 return -1; /* Negative */
254 else
255 got_positive = 1; /* Positive */
256 }
257 }
258
259 /*
260 * Return success if got a positive match. If there was a negative
261 * match, we have already returned -1 and never get here.
262 */
263 return got_positive;
264}
265
120#endif /* HAVE_CYGWIN */ 266#endif /* HAVE_CYGWIN */