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