make filter enumerator methods static
[strongswan.git] / src / libstrongswan / utils / enumerator.c
1 /*
2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2007 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "enumerator.h"
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <limits.h>
23 #include <stdio.h>
24 #include <dirent.h>
25 #include <errno.h>
26 #include <string.h>
27
28 #include <debug.h>
29
30 /**
31 * Implementation of enumerator_create_empty().enumerate
32 */
33 static bool enumerate_empty(enumerator_t *enumerator, ...)
34 {
35 return FALSE;
36 }
37
38 /**
39 * See header
40 */
41 enumerator_t* enumerator_create_empty()
42 {
43 enumerator_t *this = malloc_thing(enumerator_t);
44 this->enumerate = enumerate_empty;
45 this->destroy = (void*)free;
46 return this;
47 }
48
49 /**
50 * Enumerator implementation for directory enumerator
51 */
52 typedef struct {
53 /** implements enumerator_t */
54 enumerator_t public;
55 /** directory handle */
56 DIR *dir;
57 /** absolute path of current file */
58 char full[PATH_MAX];
59 /** where directory part of full ends and relative file gets written */
60 char *full_end;
61 } dir_enum_t;
62
63 /**
64 * Implementation of enumerator_create_directory().destroy
65 */
66 static void destroy_dir_enum(dir_enum_t *this)
67 {
68 closedir(this->dir);
69 free(this);
70 }
71
72 /**
73 * Implementation of enumerator_create_directory().enumerate
74 */
75 static bool enumerate_dir_enum(dir_enum_t *this, char **relative,
76 char **absolute, struct stat *st)
77 {
78 struct dirent *entry = readdir(this->dir);
79 size_t len, remaining;
80
81 if (!entry)
82 {
83 return FALSE;
84 }
85 if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
86 {
87 return enumerate_dir_enum(this, relative, absolute, st);
88 }
89 if (relative)
90 {
91 *relative = entry->d_name;
92 }
93 if (absolute || st)
94 {
95 remaining = sizeof(this->full) - (this->full_end - this->full);
96 len = snprintf(this->full_end, remaining, "%s", entry->d_name);
97 if (len < 0 || len >= remaining)
98 {
99 DBG1("buffer too small to enumerate file '%s'", entry->d_name);
100 return FALSE;
101 }
102 if (absolute)
103 {
104 *absolute = this->full;
105 }
106 if (st)
107 {
108 if (stat(this->full, st))
109 {
110 DBG1("stat() on '%s' failed: %s", this->full, strerror(errno));
111 return FALSE;
112 }
113 }
114 }
115 return TRUE;
116 }
117
118 /**
119 * See header
120 */
121 enumerator_t* enumerator_create_directory(char *path)
122 {
123 size_t len;
124 dir_enum_t *this = malloc_thing(dir_enum_t);
125 this->public.enumerate = (void*)enumerate_dir_enum;
126 this->public.destroy = (void*)destroy_dir_enum;
127
128 if (*path == '\0')
129 {
130 path = "./";
131 }
132 len = snprintf(this->full, sizeof(this->full)-1, "%s", path);
133 if (len < 0 || len >= sizeof(this->full)-1)
134 {
135 DBG1("path string %s too long", path);
136 free(this);
137 return NULL;
138 }
139 /* append a '/' if not already done */
140 if (this->full[len-1] != '/')
141 {
142 this->full[len++] = '/';
143 this->full[len] = '\0';
144 }
145 this->full_end = &this->full[len];
146
147 this->dir = opendir(path);
148 if (this->dir == NULL)
149 {
150 DBG1("opening directory %s failed: %s", path, strerror(errno));
151 free(this);
152 return NULL;
153 }
154 return &this->public;
155 }
156
157 /**
158 * Enumerator implementation for directory enumerator
159 */
160 typedef struct {
161 /** implements enumerator_t */
162 enumerator_t public;
163 /** string to parse */
164 char *string;
165 /** current position */
166 char *pos;
167 /** separater chars */
168 char *sep;
169 /** trim chars */
170 char *trim;
171 } token_enum_t;
172
173 /**
174 * Implementation of enumerator_create_token().destroy
175 */
176 static void destroy_token_enum(token_enum_t *this)
177 {
178 free(this->string);
179 free(this);
180 }
181
182 /**
183 * Implementation of enumerator_create_token().enumerate
184 */
185 static bool enumerate_token_enum(token_enum_t *this, char **token)
186 {
187 char *pos = NULL, *tmp, *sep, *trim;
188 bool last = FALSE;
189
190 /* trim leading characters/separators */
191 while (*this->pos)
192 {
193 trim = this->trim;
194 while (*trim)
195 {
196 if (*trim == *this->pos)
197 {
198 this->pos++;
199 break;
200 }
201 trim++;
202 }
203 sep = this->sep;
204 while (*sep)
205 {
206 if (*sep == *this->pos)
207 {
208 this->pos++;
209 break;
210 }
211 sep++;
212 }
213 if (!*trim && !*sep)
214 {
215 break;
216 }
217 }
218
219 switch (*this->pos)
220 {
221 case '"':
222 case '\'':
223 {
224 /* read quoted token */
225 tmp = strchr(this->pos + 1, *this->pos);
226 if (tmp)
227 {
228 *token = this->pos + 1;
229 *tmp = '\0';
230 this->pos = tmp + 1;
231 return TRUE;
232 }
233 /* unterminated string, FALL-THROUGH */
234 }
235 default:
236 {
237 /* find nearest separator */
238 sep = this->sep;
239 while (*sep)
240 {
241 tmp = strchr(this->pos, *sep);
242 if (tmp && (pos == NULL || tmp < pos))
243 {
244 pos = tmp;
245 }
246 sep++;
247 }
248 *token = this->pos;
249 if (pos)
250 {
251 *pos = '\0';
252 this->pos = pos + 1;
253 }
254 else
255 {
256 last = TRUE;
257 pos = this->pos = strchr(this->pos, '\0');
258 }
259 break;
260 }
261 }
262
263 /* trim trailing characters/separators */
264 pos--;
265 while (pos >= *token)
266 {
267 trim = this->trim;
268 while (*trim)
269 {
270 if (*trim == *pos)
271 {
272 *(pos--) = '\0';
273 break;
274 }
275 trim++;
276 }
277 sep = this->sep;
278 while (*sep)
279 {
280 if (*sep == *pos)
281 {
282 *(pos--) = '\0';
283 break;
284 }
285 sep++;
286 }
287 if (!*trim && !*sep)
288 {
289 break;
290 }
291 }
292
293 if (!last || pos >= *token)
294 {
295 return TRUE;
296 }
297 return FALSE;
298 }
299
300 /**
301 * See header
302 */
303 enumerator_t* enumerator_create_token(char *string, char *sep, char *trim)
304 {
305 token_enum_t *enumerator = malloc_thing(token_enum_t);
306
307 enumerator->public.enumerate = (void*)enumerate_token_enum;
308 enumerator->public.destroy = (void*)destroy_token_enum;
309 enumerator->string = strdup(string);
310 enumerator->pos = enumerator->string;
311 enumerator->sep = sep;
312 enumerator->trim = trim;
313
314 return &enumerator->public;
315 }
316
317 /**
318 * enumerator for nested enumerations
319 */
320 typedef struct {
321 /* implements enumerator_t */
322 enumerator_t public;
323 /* outer enumerator */
324 enumerator_t *outer;
325 /* inner enumerator */
326 enumerator_t *inner;
327 /* constructor for inner enumerator */
328 enumerator_t *(*create_inner)(void *outer, void *data);
329 /* data to pass to constructor above */
330 void *data;
331 /* destructor for data */
332 void (*destroy_data)(void *data);
333 } nested_enumerator_t;
334
335
336 /**
337 * Implementation of enumerator_create_nested().enumerate()
338 */
339 static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2,
340 void *v3, void *v4, void *v5)
341 {
342 while (TRUE)
343 {
344 while (this->inner == NULL)
345 {
346 void *outer;
347
348 if (!this->outer->enumerate(this->outer, &outer))
349 {
350 return FALSE;
351 }
352 this->inner = this->create_inner(outer, this->data);
353 }
354 if (this->inner->enumerate(this->inner, v1, v2, v3, v4, v5))
355 {
356 return TRUE;
357 }
358 this->inner->destroy(this->inner);
359 this->inner = NULL;
360 }
361 }
362
363 /**
364 * Implementation of enumerator_create_nested().destroy()
365 **/
366 static void destroy_nested(nested_enumerator_t *this)
367 {
368 if (this->destroy_data)
369 {
370 this->destroy_data(this->data);
371 }
372 DESTROY_IF(this->inner);
373 this->outer->destroy(this->outer);
374 free(this);
375 }
376
377 /**
378 * See header
379 */
380 enumerator_t *enumerator_create_nested(enumerator_t *outer,
381 enumerator_t *(inner_constructor)(void *outer, void *data),
382 void *data, void (*destroy_data)(void *data))
383 {
384 nested_enumerator_t *enumerator = malloc_thing(nested_enumerator_t);
385
386 enumerator->public.enumerate = (void*)enumerate_nested;
387 enumerator->public.destroy = (void*)destroy_nested;
388 enumerator->outer = outer;
389 enumerator->inner = NULL;
390 enumerator->create_inner = (void*)inner_constructor;
391 enumerator->data = data;
392 enumerator->destroy_data = destroy_data;
393
394 return &enumerator->public;
395 }
396
397 /**
398 * enumerator for filtered enumerator
399 */
400 typedef struct {
401 enumerator_t public;
402 enumerator_t *unfiltered;
403 void *data;
404 bool (*filter)(void *data, ...);
405 void (*destructor)(void *data);
406 } filter_enumerator_t;
407
408 /**
409 * Implementation of enumerator_create_filter().destroy
410 */
411 static void destroy_filter(filter_enumerator_t *this)
412 {
413 if (this->destructor)
414 {
415 this->destructor(this->data);
416 }
417 this->unfiltered->destroy(this->unfiltered);
418 free(this);
419 }
420
421 /**
422 * Implementation of enumerator_create_filter().enumerate
423 */
424 static bool enumerate_filter(filter_enumerator_t *this, void *o1, void *o2,
425 void *o3, void *o4, void *o5)
426 {
427 void *i1, *i2, *i3, *i4, *i5;
428
429 while (this->unfiltered->enumerate(this->unfiltered, &i1, &i2, &i3, &i4, &i5))
430 {
431 if (this->filter(this->data, &i1, o1, &i2, o2, &i3, o3, &i4, o4, &i5, o5))
432 {
433 return TRUE;
434 }
435 }
436 return FALSE;
437 }
438
439 /**
440 * see header
441 */
442 enumerator_t *enumerator_create_filter(enumerator_t *unfiltered,
443 bool (*filter)(void *data, ...),
444 void *data, void (*destructor)(void *data))
445 {
446 filter_enumerator_t *this = malloc_thing(filter_enumerator_t);
447
448 this->public.enumerate = (void*)enumerate_filter;
449 this->public.destroy = (void*)destroy_filter;
450 this->unfiltered = unfiltered;
451 this->filter = filter;
452 this->data = data;
453 this->destructor = destructor;
454
455 return &this->public;
456 }
457
458 /**
459 * enumerator for cleaner enumerator
460 */
461 typedef struct {
462 enumerator_t public;
463 enumerator_t *wrapped;
464 void (*cleanup)(void *data);
465 void *data;
466 } cleaner_enumerator_t;
467
468 /**
469 * Implementation of enumerator_create_cleanup().destroy
470 */
471 static void destroy_cleaner(cleaner_enumerator_t *this)
472 {
473 this->cleanup(this->data);
474 this->wrapped->destroy(this->wrapped);
475 free(this);
476 }
477
478 /**
479 * Implementation of enumerator_create_cleaner().enumerate
480 */
481 static bool enumerate_cleaner(cleaner_enumerator_t *this, void *v1, void *v2,
482 void *v3, void *v4, void *v5)
483 {
484 return this->wrapped->enumerate(this->wrapped, v1, v2, v3, v4, v5);
485 }
486
487 /**
488 * see header
489 */
490 enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
491 void (*cleanup)(void *data), void *data)
492 {
493 cleaner_enumerator_t *this = malloc_thing(cleaner_enumerator_t);
494
495 this->public.enumerate = (void*)enumerate_cleaner;
496 this->public.destroy = (void*)destroy_cleaner;
497 this->wrapped = wrapped;
498 this->cleanup = cleanup;
499 this->data = data;
500
501 return &this->public;
502 }
503
504 /**
505 * enumerator for single enumerator
506 */
507 typedef struct {
508 enumerator_t public;
509 void *item;
510 void (*cleanup)(void *item);
511 bool done;
512 } single_enumerator_t;
513
514 /**
515 * Implementation of enumerator_create_single().destroy
516 */
517 static void destroy_single(single_enumerator_t *this)
518 {
519 if (this->cleanup)
520 {
521 this->cleanup(this->item);
522 }
523 free(this);
524 }
525
526 /**
527 * Implementation of enumerator_create_single().enumerate
528 */
529 static bool enumerate_single(single_enumerator_t *this, void **item)
530 {
531 if (this->done)
532 {
533 return FALSE;
534 }
535 *item = this->item;
536 this->done = TRUE;
537 return TRUE;
538 }
539
540 /**
541 * see header
542 */
543 enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item))
544 {
545 single_enumerator_t *this = malloc_thing(single_enumerator_t);
546
547 this->public.enumerate = (void*)enumerate_single;
548 this->public.destroy = (void*)destroy_single;
549 this->item = item;
550 this->cleanup = cleanup;
551 this->done = FALSE;
552
553 return &this->public;
554 }
555