diff options
Diffstat (limited to 'openbsd-compat')
-rw-r--r-- | openbsd-compat/bsd-cygwin_util.c | 146 |
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 | |||
130 | static 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 | |||
190 | static 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 | */ | ||
214 | int | ||
215 | match_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 */ |