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