/src/strongswan/src/libstrongswan/collections/enumerator.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2008-2017 Tobias Brunner |
3 | | * Copyright (C) 2007 Martin Willi |
4 | | * |
5 | | * Copyright (C) secunet Security Networks AG |
6 | | * |
7 | | * This program is free software; you can redistribute it and/or modify it |
8 | | * under the terms of the GNU General Public License as published by the |
9 | | * Free Software Foundation; either version 2 of the License, or (at your |
10 | | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. |
11 | | * |
12 | | * This program is distributed in the hope that it will be useful, but |
13 | | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
14 | | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
15 | | * for more details. |
16 | | */ |
17 | | |
18 | | #include "enumerator.h" |
19 | | |
20 | | #include <sys/types.h> |
21 | | #include <sys/stat.h> |
22 | | #include <unistd.h> |
23 | | #include <limits.h> |
24 | | #include <stdio.h> |
25 | | #include <dirent.h> |
26 | | #include <errno.h> |
27 | | #include <string.h> |
28 | | |
29 | | #ifdef HAVE_GLOB_H |
30 | | #include <glob.h> |
31 | | #elif defined(WIN32) |
32 | | #include <fileapi.h> |
33 | | #endif /* HAVE_GLOB_H */ |
34 | | |
35 | | #include <utils/debug.h> |
36 | | |
37 | | /* |
38 | | * Described in header. |
39 | | */ |
40 | | bool enumerator_enumerate_default(enumerator_t *enumerator, ...) |
41 | 35.8k | { |
42 | 35.8k | va_list args; |
43 | 35.8k | bool result; |
44 | | |
45 | 35.8k | if (!enumerator->venumerate) |
46 | 0 | { |
47 | 0 | DBG1(DBG_LIB, "!!! ENUMERATE DEFAULT: venumerate() missing !!!"); |
48 | 0 | return FALSE; |
49 | 0 | } |
50 | 35.8k | va_start(args, enumerator); |
51 | 35.8k | result = enumerator->venumerate(enumerator, args); |
52 | 35.8k | va_end(args); |
53 | 35.8k | return result; |
54 | 35.8k | } |
55 | | |
56 | | METHOD(enumerator_t, enumerate_empty, bool, |
57 | | enumerator_t *enumerator, va_list args) |
58 | 4.37k | { |
59 | 4.37k | return FALSE; |
60 | 4.37k | } |
61 | | |
62 | | /* |
63 | | * Described in header |
64 | | */ |
65 | | enumerator_t* enumerator_create_empty() |
66 | 4.37k | { |
67 | 4.37k | enumerator_t *this; |
68 | | |
69 | 4.37k | INIT(this, |
70 | 4.37k | .enumerate = enumerator_enumerate_default, |
71 | 4.37k | .venumerate = _enumerate_empty, |
72 | 4.37k | .destroy = (void*)free, |
73 | 4.37k | ); |
74 | 4.37k | return this; |
75 | 4.37k | } |
76 | | |
77 | | /** |
78 | | * Enumerator implementation for directory enumerator |
79 | | */ |
80 | | typedef struct { |
81 | | /** implements enumerator_t */ |
82 | | enumerator_t public; |
83 | | /** directory handle */ |
84 | | DIR *dir; |
85 | | /** absolute path of current file */ |
86 | | char full[PATH_MAX]; |
87 | | /** where directory part of full ends and relative file gets written */ |
88 | | char *full_end; |
89 | | } dir_enum_t; |
90 | | |
91 | | METHOD(enumerator_t, destroy_dir_enum, void, |
92 | | dir_enum_t *this) |
93 | 0 | { |
94 | 0 | closedir(this->dir); |
95 | 0 | free(this); |
96 | 0 | } |
97 | | |
98 | | METHOD(enumerator_t, enumerate_dir_enum, bool, |
99 | | dir_enum_t *this, va_list args) |
100 | 0 | { |
101 | 0 | struct dirent *entry = readdir(this->dir); |
102 | 0 | struct stat *st; |
103 | 0 | size_t remaining; |
104 | 0 | char **relative, **absolute; |
105 | 0 | int len; |
106 | |
|
107 | 0 | VA_ARGS_VGET(args, relative, absolute, st); |
108 | |
|
109 | 0 | if (!entry) |
110 | 0 | { |
111 | 0 | return FALSE; |
112 | 0 | } |
113 | 0 | if (streq(entry->d_name, ".") || streq(entry->d_name, "..")) |
114 | 0 | { |
115 | 0 | return this->public.enumerate(&this->public, relative, absolute, st); |
116 | 0 | } |
117 | 0 | if (relative) |
118 | 0 | { |
119 | 0 | *relative = entry->d_name; |
120 | 0 | } |
121 | 0 | if (absolute || st) |
122 | 0 | { |
123 | 0 | remaining = sizeof(this->full) - (this->full_end - this->full); |
124 | 0 | len = snprintf(this->full_end, remaining, "%s", entry->d_name); |
125 | 0 | if (len < 0 || len >= remaining) |
126 | 0 | { |
127 | 0 | DBG1(DBG_LIB, "buffer too small to enumerate file '%s'", |
128 | 0 | entry->d_name); |
129 | 0 | return FALSE; |
130 | 0 | } |
131 | 0 | if (absolute) |
132 | 0 | { |
133 | 0 | *absolute = this->full; |
134 | 0 | } |
135 | 0 | if (st && stat(this->full, st)) |
136 | 0 | { |
137 | | /* try lstat() e.g. if a symlink is not valid anymore */ |
138 | 0 | if ((errno != ENOENT && errno != ENOTDIR) || lstat(this->full, st)) |
139 | 0 | { |
140 | 0 | DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->full, |
141 | 0 | strerror(errno)); |
142 | 0 | return FALSE; |
143 | 0 | } |
144 | 0 | } |
145 | 0 | } |
146 | 0 | return TRUE; |
147 | 0 | } |
148 | | |
149 | | /* |
150 | | * Described in header |
151 | | */ |
152 | | enumerator_t* enumerator_create_directory(const char *path) |
153 | 0 | { |
154 | 0 | dir_enum_t *this; |
155 | 0 | int len; |
156 | |
|
157 | 0 | INIT(this, |
158 | 0 | .public = { |
159 | 0 | .enumerate = enumerator_enumerate_default, |
160 | 0 | .venumerate = _enumerate_dir_enum, |
161 | 0 | .destroy = _destroy_dir_enum, |
162 | 0 | }, |
163 | 0 | ); |
164 | |
|
165 | 0 | if (*path == '\0') |
166 | 0 | { |
167 | 0 | path = "./"; |
168 | 0 | } |
169 | 0 | len = snprintf(this->full, sizeof(this->full)-1, "%s", path); |
170 | 0 | if (len < 0 || len >= sizeof(this->full)-1) |
171 | 0 | { |
172 | 0 | DBG1(DBG_LIB, "path string '%s' too long", path); |
173 | 0 | free(this); |
174 | 0 | return NULL; |
175 | 0 | } |
176 | | /* append a '/' if not already done */ |
177 | 0 | if (!path_is_separator(this->full[len-1])) |
178 | 0 | { |
179 | 0 | this->full[len++] = DIRECTORY_SEPARATOR[0]; |
180 | 0 | this->full[len] = '\0'; |
181 | 0 | } |
182 | 0 | this->full_end = &this->full[len]; |
183 | |
|
184 | 0 | this->dir = opendir(path); |
185 | 0 | if (!this->dir) |
186 | 0 | { |
187 | 0 | DBG1(DBG_LIB, "opening directory '%s' failed: %s", path, |
188 | 0 | strerror(errno)); |
189 | 0 | free(this); |
190 | 0 | return NULL; |
191 | 0 | } |
192 | 0 | return &this->public; |
193 | 0 | } |
194 | | |
195 | | #ifdef HAVE_GLOB_H |
196 | | |
197 | | /** |
198 | | * Enumerator implementation for glob enumerator |
199 | | */ |
200 | | typedef struct { |
201 | | /** implements enumerator_t */ |
202 | | enumerator_t public; |
203 | | /** glob data */ |
204 | | glob_t glob; |
205 | | /** iteration count */ |
206 | | u_int pos; |
207 | | } glob_enum_t; |
208 | | |
209 | | METHOD(enumerator_t, destroy_glob_enum, void, |
210 | | glob_enum_t *this) |
211 | 2.17k | { |
212 | 2.17k | globfree(&this->glob); |
213 | 2.17k | free(this); |
214 | 2.17k | } |
215 | | |
216 | | METHOD(enumerator_t, enumerate_glob_enum, bool, |
217 | | glob_enum_t *this, va_list args) |
218 | 2.17k | { |
219 | 2.17k | struct stat *st; |
220 | 2.17k | char *match; |
221 | 2.17k | char **file; |
222 | | |
223 | 2.17k | VA_ARGS_VGET(args, file, st); |
224 | | |
225 | 2.17k | if (this->pos >= this->glob.gl_pathc) |
226 | 2.17k | { |
227 | 2.17k | return FALSE; |
228 | 2.17k | } |
229 | 0 | match = this->glob.gl_pathv[this->pos++]; |
230 | 0 | if (file) |
231 | 0 | { |
232 | 0 | *file = match; |
233 | 0 | } |
234 | 0 | if (st && stat(match, st)) |
235 | 0 | { |
236 | 0 | DBG1(DBG_LIB, "stat() on '%s' failed: %s", match, |
237 | 0 | strerror(errno)); |
238 | 0 | return FALSE; |
239 | 0 | } |
240 | 0 | return TRUE; |
241 | 0 | } |
242 | | |
243 | | /* |
244 | | * Described in header |
245 | | */ |
246 | | enumerator_t* enumerator_create_glob(const char *pattern) |
247 | 2.17k | { |
248 | 2.17k | glob_enum_t *this; |
249 | 2.17k | int status; |
250 | | |
251 | 2.17k | if (!pattern) |
252 | 0 | { |
253 | 0 | return enumerator_create_empty(); |
254 | 0 | } |
255 | | |
256 | 2.17k | INIT(this, |
257 | 2.17k | .public = { |
258 | 2.17k | .enumerate = enumerator_enumerate_default, |
259 | 2.17k | .venumerate = _enumerate_glob_enum, |
260 | 2.17k | .destroy = _destroy_glob_enum, |
261 | 2.17k | }, |
262 | 2.17k | ); |
263 | | |
264 | 2.17k | status = glob(pattern, GLOB_ERR, NULL, &this->glob); |
265 | 2.17k | if (status == GLOB_NOMATCH) |
266 | 2.17k | { |
267 | 2.17k | DBG1(DBG_LIB, "no files found matching '%s'", pattern); |
268 | 2.17k | } |
269 | 0 | else if (status != 0) |
270 | 0 | { |
271 | 0 | DBG1(DBG_LIB, "expanding file pattern '%s' failed: %s", pattern, |
272 | 0 | strerror(errno)); |
273 | 0 | } |
274 | 2.17k | return &this->public; |
275 | 2.17k | } |
276 | | |
277 | | #elif defined(WIN32) /* HAVE_GLOB_H */ |
278 | | |
279 | | /** |
280 | | * Enumerator implementation for glob enumerator on Windows |
281 | | */ |
282 | | typedef struct { |
283 | | /** implements enumerator_t */ |
284 | | enumerator_t public; |
285 | | /** search handle */ |
286 | | HANDLE handle; |
287 | | /** current file path */ |
288 | | char path[PATH_MAX]; |
289 | | /** base path */ |
290 | | char *base; |
291 | | } glob_enum_t; |
292 | | |
293 | | METHOD(enumerator_t, destroy_glob_enum, void, |
294 | | glob_enum_t *this) |
295 | | { |
296 | | if (this->handle != INVALID_HANDLE_VALUE) |
297 | | { |
298 | | FindClose(this->handle); |
299 | | } |
300 | | free(this->base); |
301 | | free(this); |
302 | | } |
303 | | |
304 | | /** |
305 | | * Create the combined path from the given file data |
306 | | */ |
307 | | static bool combine_glob_path(glob_enum_t *this, WIN32_FIND_DATA *data) |
308 | | { |
309 | | if (snprintf(this->path, sizeof(this->path), "%s%s%s", this->base, |
310 | | DIRECTORY_SEPARATOR, data->cFileName) >= sizeof(this->path)) |
311 | | { |
312 | | DBG1(DBG_LIB, "path for '%s' too long, ignored", data->cFileName); |
313 | | return FALSE; |
314 | | } |
315 | | return TRUE; |
316 | | } |
317 | | |
318 | | /** |
319 | | * Return the path and stat data for the current file |
320 | | */ |
321 | | static bool enumerate_glob_enum_data(glob_enum_t *this, va_list args) |
322 | | { |
323 | | struct stat *st; |
324 | | char **file; |
325 | | |
326 | | VA_ARGS_VGET(args, file, st); |
327 | | |
328 | | if (file) |
329 | | { |
330 | | *file = this->path; |
331 | | } |
332 | | if (st && stat(this->path, st)) |
333 | | { |
334 | | DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->path, |
335 | | strerror(errno)); |
336 | | return FALSE; |
337 | | } |
338 | | return TRUE; |
339 | | } |
340 | | |
341 | | METHOD(enumerator_t, enumerate_glob_enum, bool, |
342 | | glob_enum_t *this, va_list args) |
343 | | { |
344 | | WIN32_FIND_DATA data; |
345 | | |
346 | | do |
347 | | { |
348 | | if (!FindNextFile(this->handle, &data)) |
349 | | { |
350 | | return FALSE; |
351 | | } |
352 | | } |
353 | | while (!combine_glob_path(this, &data)); |
354 | | |
355 | | return enumerate_glob_enum_data(this, args); |
356 | | } |
357 | | |
358 | | METHOD(enumerator_t, enumerate_glob_enum_first, bool, |
359 | | glob_enum_t *this, va_list args) |
360 | | { |
361 | | if (enumerate_glob_enum_data(this, args)) |
362 | | { |
363 | | this->public.venumerate = _enumerate_glob_enum; |
364 | | return TRUE; |
365 | | } |
366 | | return FALSE; |
367 | | } |
368 | | |
369 | | /* |
370 | | * Described in header |
371 | | */ |
372 | | enumerator_t *enumerator_create_glob(const char *pattern) |
373 | | { |
374 | | glob_enum_t *this; |
375 | | WIN32_FIND_DATA data; |
376 | | |
377 | | if (!pattern) |
378 | | { |
379 | | return enumerator_create_empty(); |
380 | | } |
381 | | |
382 | | INIT(this, |
383 | | .public = { |
384 | | .enumerate = enumerator_enumerate_default, |
385 | | .venumerate = _enumerate_glob_enum_first, |
386 | | .destroy = _destroy_glob_enum, |
387 | | }, |
388 | | .base = path_dirname(pattern), |
389 | | ); |
390 | | |
391 | | this->handle = FindFirstFile(pattern, &data); |
392 | | if (this->handle == INVALID_HANDLE_VALUE) |
393 | | { |
394 | | if (GetLastError() == ERROR_FILE_NOT_FOUND || |
395 | | GetLastError() == ERROR_PATH_NOT_FOUND) |
396 | | { |
397 | | DBG1(DBG_LIB, "no files found matching '%s'", pattern); |
398 | | } |
399 | | else |
400 | | { |
401 | | DBG1(DBG_LIB, "FindFirstFile failed for pattern '%s' (%d)", pattern, |
402 | | GetLastError()); |
403 | | } |
404 | | destroy_glob_enum(this); |
405 | | return enumerator_create_empty(); |
406 | | } |
407 | | else if (!combine_glob_path(this, &data)) |
408 | | { /* check the next file if we can't combine the path for the first one */ |
409 | | this->public.venumerate = _enumerate_glob_enum; |
410 | | } |
411 | | return &this->public; |
412 | | } |
413 | | |
414 | | #else /* HAVE_GLOB_H */ |
415 | | |
416 | | enumerator_t* enumerator_create_glob(const char *pattern) |
417 | | { |
418 | | return NULL; |
419 | | } |
420 | | |
421 | | #endif /* HAVE_GLOB_H */ |
422 | | |
423 | | /** |
424 | | * Enumerator implementation for token enumerator |
425 | | */ |
426 | | typedef struct { |
427 | | /** implements enumerator_t */ |
428 | | enumerator_t public; |
429 | | /** string to parse */ |
430 | | char *string; |
431 | | /** current position */ |
432 | | char *pos; |
433 | | /** separator chars */ |
434 | | const char *sep; |
435 | | /** trim chars */ |
436 | | const char *trim; |
437 | | } token_enum_t; |
438 | | |
439 | | METHOD(enumerator_t, destroy_token_enum, void, |
440 | | token_enum_t *this) |
441 | 0 | { |
442 | 0 | free(this->string); |
443 | 0 | free(this); |
444 | 0 | } |
445 | | |
446 | | METHOD(enumerator_t, enumerate_token_enum, bool, |
447 | | token_enum_t *this, va_list args) |
448 | 0 | { |
449 | 0 | const char *sep, *trim; |
450 | 0 | char *pos = NULL, *tmp, **token; |
451 | 0 | bool last = FALSE; |
452 | |
|
453 | 0 | VA_ARGS_VGET(args, token); |
454 | | |
455 | | /* trim leading characters/separators */ |
456 | 0 | while (*this->pos) |
457 | 0 | { |
458 | 0 | trim = this->trim; |
459 | 0 | while (*trim) |
460 | 0 | { |
461 | 0 | if (*trim == *this->pos) |
462 | 0 | { |
463 | 0 | this->pos++; |
464 | 0 | break; |
465 | 0 | } |
466 | 0 | trim++; |
467 | 0 | } |
468 | 0 | sep = this->sep; |
469 | 0 | while (*sep) |
470 | 0 | { |
471 | 0 | if (*sep == *this->pos) |
472 | 0 | { |
473 | 0 | this->pos++; |
474 | 0 | break; |
475 | 0 | } |
476 | 0 | sep++; |
477 | 0 | } |
478 | 0 | if (!*trim && !*sep) |
479 | 0 | { |
480 | 0 | break; |
481 | 0 | } |
482 | 0 | } |
483 | |
|
484 | 0 | switch (*this->pos) |
485 | 0 | { |
486 | 0 | case '"': |
487 | 0 | case '\'': |
488 | 0 | { |
489 | | /* read quoted token */ |
490 | 0 | tmp = strchr(this->pos + 1, *this->pos); |
491 | 0 | if (tmp) |
492 | 0 | { |
493 | 0 | *token = this->pos + 1; |
494 | 0 | *tmp = '\0'; |
495 | 0 | this->pos = tmp + 1; |
496 | 0 | return TRUE; |
497 | 0 | } |
498 | | /* unterminated string, FALL-THROUGH */ |
499 | 0 | } |
500 | 0 | default: |
501 | 0 | { |
502 | | /* find nearest separator */ |
503 | 0 | sep = this->sep; |
504 | 0 | while (*sep) |
505 | 0 | { |
506 | 0 | tmp = strchr(this->pos, *sep); |
507 | 0 | if (tmp && (pos == NULL || tmp < pos)) |
508 | 0 | { |
509 | 0 | pos = tmp; |
510 | 0 | } |
511 | 0 | sep++; |
512 | 0 | } |
513 | 0 | *token = this->pos; |
514 | 0 | if (pos) |
515 | 0 | { |
516 | 0 | *pos = '\0'; |
517 | 0 | this->pos = pos + 1; |
518 | 0 | } |
519 | 0 | else |
520 | 0 | { |
521 | 0 | last = TRUE; |
522 | 0 | pos = this->pos = strchr(this->pos, '\0'); |
523 | 0 | } |
524 | 0 | break; |
525 | 0 | } |
526 | 0 | } |
527 | | |
528 | | /* trim trailing characters */ |
529 | 0 | pos--; |
530 | 0 | while (pos >= *token) |
531 | 0 | { |
532 | 0 | trim = this->trim; |
533 | 0 | while (*trim) |
534 | 0 | { |
535 | 0 | if (*trim == *pos) |
536 | 0 | { |
537 | 0 | *(pos--) = '\0'; |
538 | 0 | break; |
539 | 0 | } |
540 | 0 | trim++; |
541 | 0 | } |
542 | 0 | if (!*trim) |
543 | 0 | { |
544 | 0 | break; |
545 | 0 | } |
546 | 0 | } |
547 | |
|
548 | 0 | if (!last || pos >= *token) |
549 | 0 | { |
550 | 0 | return TRUE; |
551 | 0 | } |
552 | 0 | return FALSE; |
553 | 0 | } |
554 | | |
555 | | /* |
556 | | * Described in header |
557 | | */ |
558 | | enumerator_t* enumerator_create_token(const char *string, const char *sep, |
559 | | const char *trim) |
560 | 0 | { |
561 | 0 | token_enum_t *this; |
562 | |
|
563 | 0 | INIT(this, |
564 | 0 | .public = { |
565 | 0 | .enumerate = enumerator_enumerate_default, |
566 | 0 | .venumerate = _enumerate_token_enum, |
567 | 0 | .destroy = _destroy_token_enum, |
568 | 0 | }, |
569 | 0 | .string = strdup(string), |
570 | 0 | .sep = sep, |
571 | 0 | .trim = trim, |
572 | 0 | ); |
573 | 0 | this->pos = this->string; |
574 | |
|
575 | 0 | return &this->public; |
576 | 0 | } |
577 | | |
578 | | /** |
579 | | * Enumerator for nested enumerations |
580 | | */ |
581 | | typedef struct { |
582 | | enumerator_t public; |
583 | | enumerator_t *outer; |
584 | | enumerator_t *inner; |
585 | | enumerator_t *(*create_inner)(void *outer, void *data); |
586 | | void *data; |
587 | | void (*destructor)(void *data); |
588 | | } nested_enumerator_t; |
589 | | |
590 | | |
591 | | METHOD(enumerator_t, enumerate_nested, bool, |
592 | | nested_enumerator_t *this, va_list args) |
593 | 0 | { |
594 | 0 | while (TRUE) |
595 | 0 | { |
596 | 0 | while (!this->inner) |
597 | 0 | { |
598 | 0 | void *outer; |
599 | |
|
600 | 0 | if (!this->outer->enumerate(this->outer, &outer)) |
601 | 0 | { |
602 | 0 | return FALSE; |
603 | 0 | } |
604 | 0 | this->inner = this->create_inner(outer, this->data); |
605 | 0 | if (this->inner && !this->inner->venumerate) |
606 | 0 | { |
607 | 0 | DBG1(DBG_LIB, "!!! ENUMERATE NESTED: venumerate() missing !!!"); |
608 | 0 | return FALSE; |
609 | 0 | } |
610 | 0 | } |
611 | 0 | if (this->inner->venumerate(this->inner, args)) |
612 | 0 | { |
613 | 0 | return TRUE; |
614 | 0 | } |
615 | 0 | this->inner->destroy(this->inner); |
616 | 0 | this->inner = NULL; |
617 | 0 | } |
618 | 0 | } |
619 | | |
620 | | METHOD(enumerator_t, destroy_nested, void, |
621 | | nested_enumerator_t *this) |
622 | 0 | { |
623 | 0 | if (this->destructor) |
624 | 0 | { |
625 | 0 | this->destructor(this->data); |
626 | 0 | } |
627 | 0 | DESTROY_IF(this->inner); |
628 | 0 | this->outer->destroy(this->outer); |
629 | 0 | free(this); |
630 | 0 | } |
631 | | |
632 | | /* |
633 | | * Described in header |
634 | | */ |
635 | | enumerator_t *enumerator_create_nested(enumerator_t *outer, |
636 | | enumerator_t *(inner_constructor)(void *outer, void *data), |
637 | | void *data, void (*destructor)(void *data)) |
638 | 0 | { |
639 | 0 | nested_enumerator_t *this; |
640 | |
|
641 | 0 | INIT(this, |
642 | 0 | .public = { |
643 | 0 | .enumerate = enumerator_enumerate_default, |
644 | 0 | .venumerate = _enumerate_nested, |
645 | 0 | .destroy = _destroy_nested, |
646 | 0 | }, |
647 | 0 | .outer = outer, |
648 | 0 | .create_inner = inner_constructor, |
649 | 0 | .data = data, |
650 | 0 | .destructor = destructor, |
651 | 0 | ); |
652 | 0 | return &this->public; |
653 | 0 | } |
654 | | |
655 | | /** |
656 | | * Enumerator for filtered enumerator |
657 | | */ |
658 | | typedef struct { |
659 | | enumerator_t public; |
660 | | enumerator_t *orig; |
661 | | void *data; |
662 | | bool (*filter)(void*,enumerator_t*,va_list); |
663 | | void (*destructor)(void *data); |
664 | | } filter_enumerator_t; |
665 | | |
666 | | METHOD(enumerator_t, destroy_filter, void, |
667 | | filter_enumerator_t *this) |
668 | 0 | { |
669 | 0 | if (this->destructor) |
670 | 0 | { |
671 | 0 | this->destructor(this->data); |
672 | 0 | } |
673 | 0 | this->orig->destroy(this->orig); |
674 | 0 | free(this); |
675 | 0 | } |
676 | | |
677 | | METHOD(enumerator_t, enumerate_filter, bool, |
678 | | filter_enumerator_t *this, va_list args) |
679 | 0 | { |
680 | 0 | bool result = FALSE; |
681 | |
|
682 | 0 | if (this->filter(this->data, this->orig, args)) |
683 | 0 | { |
684 | 0 | result = TRUE; |
685 | 0 | } |
686 | 0 | return result; |
687 | 0 | } |
688 | | |
689 | | /* |
690 | | * Described in header |
691 | | */ |
692 | | enumerator_t *enumerator_create_filter(enumerator_t *orig, |
693 | | bool (*filter)(void *data, enumerator_t *orig, va_list args), |
694 | | void *data, void (*destructor)(void *data)) |
695 | 0 | { |
696 | 0 | filter_enumerator_t *this; |
697 | |
|
698 | 0 | INIT(this, |
699 | 0 | .public = { |
700 | 0 | .enumerate = enumerator_enumerate_default, |
701 | 0 | .venumerate = _enumerate_filter, |
702 | 0 | .destroy = _destroy_filter, |
703 | 0 | }, |
704 | 0 | .orig = orig, |
705 | 0 | .filter = filter, |
706 | 0 | .data = data, |
707 | 0 | .destructor = destructor, |
708 | 0 | ); |
709 | 0 | return &this->public; |
710 | 0 | } |
711 | | |
712 | | /** |
713 | | * Enumerator for cleaner enumerator |
714 | | */ |
715 | | typedef struct { |
716 | | enumerator_t public; |
717 | | enumerator_t *wrapped; |
718 | | void (*cleanup)(void *data); |
719 | | void *data; |
720 | | } cleaner_enumerator_t; |
721 | | |
722 | | METHOD(enumerator_t, destroy_cleaner, void, |
723 | | cleaner_enumerator_t *this) |
724 | 0 | { |
725 | 0 | this->cleanup(this->data); |
726 | 0 | this->wrapped->destroy(this->wrapped); |
727 | 0 | free(this); |
728 | 0 | } |
729 | | |
730 | | METHOD(enumerator_t, enumerate_cleaner, bool, |
731 | | cleaner_enumerator_t *this, va_list args) |
732 | 0 | { |
733 | 0 | if (!this->wrapped->venumerate) |
734 | 0 | { |
735 | 0 | DBG1(DBG_LIB, "!!! CLEANER ENUMERATOR: venumerate() missing !!!"); |
736 | 0 | return FALSE; |
737 | 0 | } |
738 | 0 | return this->wrapped->venumerate(this->wrapped, args); |
739 | 0 | } |
740 | | |
741 | | /* |
742 | | * Described in header |
743 | | */ |
744 | | enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped, |
745 | | void (*cleanup)(void *data), void *data) |
746 | 0 | { |
747 | 0 | cleaner_enumerator_t *this; |
748 | |
|
749 | 0 | INIT(this, |
750 | 0 | .public = { |
751 | 0 | .enumerate = enumerator_enumerate_default, |
752 | 0 | .venumerate = _enumerate_cleaner, |
753 | 0 | .destroy = _destroy_cleaner, |
754 | 0 | }, |
755 | 0 | .wrapped = wrapped, |
756 | 0 | .cleanup = cleanup, |
757 | 0 | .data = data, |
758 | 0 | ); |
759 | 0 | return &this->public; |
760 | 0 | } |
761 | | |
762 | | /** |
763 | | * Enumerator for single enumerator |
764 | | */ |
765 | | typedef struct { |
766 | | enumerator_t public; |
767 | | void *item; |
768 | | void (*cleanup)(void *item); |
769 | | bool done; |
770 | | } single_enumerator_t; |
771 | | |
772 | | METHOD(enumerator_t, destroy_single, void, |
773 | | single_enumerator_t *this) |
774 | 0 | { |
775 | 0 | if (this->cleanup) |
776 | 0 | { |
777 | 0 | this->cleanup(this->item); |
778 | 0 | } |
779 | 0 | free(this); |
780 | 0 | } |
781 | | |
782 | | METHOD(enumerator_t, enumerate_single, bool, |
783 | | single_enumerator_t *this, va_list args) |
784 | 0 | { |
785 | 0 | void **item; |
786 | |
|
787 | 0 | VA_ARGS_VGET(args, item); |
788 | 0 | if (this->done) |
789 | 0 | { |
790 | 0 | return FALSE; |
791 | 0 | } |
792 | 0 | *item = this->item; |
793 | 0 | this->done = TRUE; |
794 | 0 | return TRUE; |
795 | 0 | } |
796 | | |
797 | | /* |
798 | | * Described in header |
799 | | */ |
800 | | enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item)) |
801 | 0 | { |
802 | 0 | single_enumerator_t *this; |
803 | |
|
804 | 0 | INIT(this, |
805 | 0 | .public = { |
806 | 0 | .enumerate = enumerator_enumerate_default, |
807 | 0 | .venumerate = _enumerate_single, |
808 | 0 | .destroy = _destroy_single, |
809 | 0 | }, |
810 | 0 | .item = item, |
811 | 0 | .cleanup = cleanup, |
812 | 0 | ); |
813 | 0 | return &this->public; |
814 | 0 | } |