f80cdabd2ddd8ac045b9a3449bf69d4fd3ab73b0
[strongswan.git] / src / libstrongswan / collections / 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 <utils/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 remaining;
80 int len;
81
82 if (!entry)
83 {
84 return FALSE;
85 }
86 if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
87 {
88 return enumerate_dir_enum(this, relative, absolute, st);
89 }
90 if (relative)
91 {
92 *relative = entry->d_name;
93 }
94 if (absolute || st)
95 {
96 remaining = sizeof(this->full) - (this->full_end - this->full);
97 len = snprintf(this->full_end, remaining, "%s", entry->d_name);
98 if (len < 0 || len >= remaining)
99 {
100 DBG1(DBG_LIB, "buffer too small to enumerate file '%s'",
101 entry->d_name);
102 return FALSE;
103 }
104 if (absolute)
105 {
106 *absolute = this->full;
107 }
108 if (st)
109 {
110 if (stat(this->full, st))
111 {
112 DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->full,
113 strerror(errno));
114 return FALSE;
115 }
116 }
117 }
118 return TRUE;
119 }
120
121 /**
122 * See header
123 */
124 enumerator_t* enumerator_create_directory(const char *path)
125 {
126 int len;
127 dir_enum_t *this = malloc_thing(dir_enum_t);
128 this->public.enumerate = (void*)enumerate_dir_enum;
129 this->public.destroy = (void*)destroy_dir_enum;
130
131 if (*path == '\0')
132 {
133 path = "./";
134 }
135 len = snprintf(this->full, sizeof(this->full)-1, "%s", path);
136 if (len < 0 || len >= sizeof(this->full)-1)
137 {
138 DBG1(DBG_LIB, "path string '%s' too long", path);
139 free(this);
140 return NULL;
141 }
142 /* append a '/' if not already done */
143 if (this->full[len-1] != '/')
144 {
145 this->full[len++] = '/';
146 this->full[len] = '\0';
147 }
148 this->full_end = &this->full[len];
149
150 this->dir = opendir(path);
151 if (this->dir == NULL)
152 {
153 DBG1(DBG_LIB, "opening directory '%s' failed: %s", path, strerror(errno));
154 free(this);
155 return NULL;
156 }
157 return &this->public;
158 }
159
160 /**
161 * Enumerator implementation for directory enumerator
162 */
163 typedef struct {
164 /** implements enumerator_t */
165 enumerator_t public;
166 /** string to parse */
167 char *string;
168 /** current position */
169 char *pos;
170 /** separater chars */
171 const char *sep;
172 /** trim chars */
173 const char *trim;
174 } token_enum_t;
175
176 /**
177 * Implementation of enumerator_create_token().destroy
178 */
179 static void destroy_token_enum(token_enum_t *this)
180 {
181 free(this->string);
182 free(this);
183 }
184
185 /**
186 * Implementation of enumerator_create_token().enumerate
187 */
188 static bool enumerate_token_enum(token_enum_t *this, char **token)
189 {
190 const char *sep, *trim;
191 char *pos = NULL, *tmp;
192 bool last = FALSE;
193
194 /* trim leading characters/separators */
195 while (*this->pos)
196 {
197 trim = this->trim;
198 while (*trim)
199 {
200 if (*trim == *this->pos)
201 {
202 this->pos++;
203 break;
204 }
205 trim++;
206 }
207 sep = this->sep;
208 while (*sep)
209 {
210 if (*sep == *this->pos)
211 {
212 this->pos++;
213 break;
214 }
215 sep++;
216 }
217 if (!*trim && !*sep)
218 {
219 break;
220 }
221 }
222
223 switch (*this->pos)
224 {
225 case '"':
226 case '\'':
227 {
228 /* read quoted token */
229 tmp = strchr(this->pos + 1, *this->pos);
230 if (tmp)
231 {
232 *token = this->pos + 1;
233 *tmp = '\0';
234 this->pos = tmp + 1;
235 return TRUE;
236 }
237 /* unterminated string, FALL-THROUGH */
238 }
239 default:
240 {
241 /* find nearest separator */
242 sep = this->sep;
243 while (*sep)
244 {
245 tmp = strchr(this->pos, *sep);
246 if (tmp && (pos == NULL || tmp < pos))
247 {
248 pos = tmp;
249 }
250 sep++;
251 }
252 *token = this->pos;
253 if (pos)
254 {
255 *pos = '\0';
256 this->pos = pos + 1;
257 }
258 else
259 {
260 last = TRUE;
261 pos = this->pos = strchr(this->pos, '\0');
262 }
263 break;
264 }
265 }
266
267 /* trim trailing characters/separators */
268 pos--;
269 while (pos >= *token)
270 {
271 trim = this->trim;
272 while (*trim)
273 {
274 if (*trim == *pos)
275 {
276 *(pos--) = '\0';
277 break;
278 }
279 trim++;
280 }
281 sep = this->sep;
282 while (*sep)
283 {
284 if (*sep == *pos)
285 {
286 *(pos--) = '\0';
287 break;
288 }
289 sep++;
290 }
291 if (!*trim && !*sep)
292 {
293 break;
294 }
295 }
296
297 if (!last || pos >= *token)
298 {
299 return TRUE;
300 }
301 return FALSE;
302 }
303
304 /**
305 * See header
306 */
307 enumerator_t* enumerator_create_token(const char *string, const char *sep,
308 const char *trim)
309 {
310 token_enum_t *enumerator = malloc_thing(token_enum_t);
311
312 enumerator->public.enumerate = (void*)enumerate_token_enum;
313 enumerator->public.destroy = (void*)destroy_token_enum;
314 enumerator->string = strdup(string);
315 enumerator->pos = enumerator->string;
316 enumerator->sep = sep;
317 enumerator->trim = trim;
318
319 return &enumerator->public;
320 }
321
322 /**
323 * enumerator for nested enumerations
324 */
325 typedef struct {
326 /* implements enumerator_t */
327 enumerator_t public;
328 /* outer enumerator */
329 enumerator_t *outer;
330 /* inner enumerator */
331 enumerator_t *inner;
332 /* constructor for inner enumerator */
333 enumerator_t *(*create_inner)(void *outer, void *data);
334 /* data to pass to constructor above */
335 void *data;
336 /* destructor for data */
337 void (*destroy_data)(void *data);
338 } nested_enumerator_t;
339
340
341 /**
342 * Implementation of enumerator_create_nested().enumerate()
343 */
344 static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2,
345 void *v3, void *v4, void *v5)
346 {
347 while (TRUE)
348 {
349 while (this->inner == NULL)
350 {
351 void *outer;
352
353 if (!this->outer->enumerate(this->outer, &outer))
354 {
355 return FALSE;
356 }
357 this->inner = this->create_inner(outer, this->data);
358 }
359 if (this->inner->enumerate(this->inner, v1, v2, v3, v4, v5))
360 {
361 return TRUE;
362 }
363 this->inner->destroy(this->inner);
364 this->inner = NULL;
365 }
366 }
367
368 /**
369 * Implementation of enumerator_create_nested().destroy()
370 **/
371 static void destroy_nested(nested_enumerator_t *this)
372 {
373 if (this->destroy_data)
374 {
375 this->destroy_data(this->data);
376 }
377 DESTROY_IF(this->inner);
378 this->outer->destroy(this->outer);
379 free(this);
380 }
381
382 /**
383 * See header
384 */
385 enumerator_t *enumerator_create_nested(enumerator_t *outer,
386 enumerator_t *(inner_constructor)(void *outer, void *data),
387 void *data, void (*destroy_data)(void *data))
388 {
389 nested_enumerator_t *enumerator = malloc_thing(nested_enumerator_t);
390
391 enumerator->public.enumerate = (void*)enumerate_nested;
392 enumerator->public.destroy = (void*)destroy_nested;
393 enumerator->outer = outer;
394 enumerator->inner = NULL;
395 enumerator->create_inner = (void*)inner_constructor;
396 enumerator->data = data;
397 enumerator->destroy_data = destroy_data;
398
399 return &enumerator->public;
400 }
401
402 /**
403 * enumerator for filtered enumerator
404 */
405 typedef struct {
406 enumerator_t public;
407 enumerator_t *unfiltered;
408 void *data;
409 bool (*filter)(void *data, ...);
410 void (*destructor)(void *data);
411 } filter_enumerator_t;
412
413 /**
414 * Implementation of enumerator_create_filter().destroy
415 */
416 static void destroy_filter(filter_enumerator_t *this)
417 {
418 if (this->destructor)
419 {
420 this->destructor(this->data);
421 }
422 this->unfiltered->destroy(this->unfiltered);
423 free(this);
424 }
425
426 /**
427 * Implementation of enumerator_create_filter().enumerate
428 */
429 static bool enumerate_filter(filter_enumerator_t *this, void *o1, void *o2,
430 void *o3, void *o4, void *o5)
431 {
432 void *i1, *i2, *i3, *i4, *i5;
433
434 while (this->unfiltered->enumerate(this->unfiltered, &i1, &i2, &i3, &i4, &i5))
435 {
436 if (this->filter(this->data, &i1, o1, &i2, o2, &i3, o3, &i4, o4, &i5, o5))
437 {
438 return TRUE;
439 }
440 }
441 return FALSE;
442 }
443
444 /**
445 * see header
446 */
447 enumerator_t *enumerator_create_filter(enumerator_t *unfiltered,
448 bool (*filter)(void *data, ...),
449 void *data, void (*destructor)(void *data))
450 {
451 filter_enumerator_t *this = malloc_thing(filter_enumerator_t);
452
453 this->public.enumerate = (void*)enumerate_filter;
454 this->public.destroy = (void*)destroy_filter;
455 this->unfiltered = unfiltered;
456 this->filter = filter;
457 this->data = data;
458 this->destructor = destructor;
459
460 return &this->public;
461 }
462
463 /**
464 * enumerator for cleaner enumerator
465 */
466 typedef struct {
467 enumerator_t public;
468 enumerator_t *wrapped;
469 void (*cleanup)(void *data);
470 void *data;
471 } cleaner_enumerator_t;
472
473 /**
474 * Implementation of enumerator_create_cleanup().destroy
475 */
476 static void destroy_cleaner(cleaner_enumerator_t *this)
477 {
478 this->cleanup(this->data);
479 this->wrapped->destroy(this->wrapped);
480 free(this);
481 }
482
483 /**
484 * Implementation of enumerator_create_cleaner().enumerate
485 */
486 static bool enumerate_cleaner(cleaner_enumerator_t *this, void *v1, void *v2,
487 void *v3, void *v4, void *v5)
488 {
489 return this->wrapped->enumerate(this->wrapped, v1, v2, v3, v4, v5);
490 }
491
492 /**
493 * see header
494 */
495 enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
496 void (*cleanup)(void *data), void *data)
497 {
498 cleaner_enumerator_t *this = malloc_thing(cleaner_enumerator_t);
499
500 this->public.enumerate = (void*)enumerate_cleaner;
501 this->public.destroy = (void*)destroy_cleaner;
502 this->wrapped = wrapped;
503 this->cleanup = cleanup;
504 this->data = data;
505
506 return &this->public;
507 }
508
509 /**
510 * enumerator for single enumerator
511 */
512 typedef struct {
513 enumerator_t public;
514 void *item;
515 void (*cleanup)(void *item);
516 bool done;
517 } single_enumerator_t;
518
519 /**
520 * Implementation of enumerator_create_single().destroy
521 */
522 static void destroy_single(single_enumerator_t *this)
523 {
524 if (this->cleanup)
525 {
526 this->cleanup(this->item);
527 }
528 free(this);
529 }
530
531 /**
532 * Implementation of enumerator_create_single().enumerate
533 */
534 static bool enumerate_single(single_enumerator_t *this, void **item)
535 {
536 if (this->done)
537 {
538 return FALSE;
539 }
540 *item = this->item;
541 this->done = TRUE;
542 return TRUE;
543 }
544
545 /**
546 * see header
547 */
548 enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item))
549 {
550 single_enumerator_t *this = malloc_thing(single_enumerator_t);
551
552 this->public.enumerate = (void*)enumerate_single;
553 this->public.destroy = (void*)destroy_single;
554 this->item = item;
555 this->cleanup = cleanup;
556 this->done = FALSE;
557
558 return &this->public;
559 }
560