array: Number of items in get_size() is unsigned
[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 */
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 if (!*trim)
282 {
283 break;
284 }
285 }
286
287 if (!last || pos >= *token)
288 {
289 return TRUE;
290 }
291 return FALSE;
292 }
293
294 /**
295 * See header
296 */
297 enumerator_t* enumerator_create_token(const char *string, const char *sep,
298 const char *trim)
299 {
300 token_enum_t *enumerator = malloc_thing(token_enum_t);
301
302 enumerator->public.enumerate = (void*)enumerate_token_enum;
303 enumerator->public.destroy = (void*)destroy_token_enum;
304 enumerator->string = strdup(string);
305 enumerator->pos = enumerator->string;
306 enumerator->sep = sep;
307 enumerator->trim = trim;
308
309 return &enumerator->public;
310 }
311
312 /**
313 * enumerator for nested enumerations
314 */
315 typedef struct {
316 /* implements enumerator_t */
317 enumerator_t public;
318 /* outer enumerator */
319 enumerator_t *outer;
320 /* inner enumerator */
321 enumerator_t *inner;
322 /* constructor for inner enumerator */
323 enumerator_t *(*create_inner)(void *outer, void *data);
324 /* data to pass to constructor above */
325 void *data;
326 /* destructor for data */
327 void (*destroy_data)(void *data);
328 } nested_enumerator_t;
329
330
331 /**
332 * Implementation of enumerator_create_nested().enumerate()
333 */
334 static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2,
335 void *v3, void *v4, void *v5)
336 {
337 while (TRUE)
338 {
339 while (this->inner == NULL)
340 {
341 void *outer;
342
343 if (!this->outer->enumerate(this->outer, &outer))
344 {
345 return FALSE;
346 }
347 this->inner = this->create_inner(outer, this->data);
348 }
349 if (this->inner->enumerate(this->inner, v1, v2, v3, v4, v5))
350 {
351 return TRUE;
352 }
353 this->inner->destroy(this->inner);
354 this->inner = NULL;
355 }
356 }
357
358 /**
359 * Implementation of enumerator_create_nested().destroy()
360 **/
361 static void destroy_nested(nested_enumerator_t *this)
362 {
363 if (this->destroy_data)
364 {
365 this->destroy_data(this->data);
366 }
367 DESTROY_IF(this->inner);
368 this->outer->destroy(this->outer);
369 free(this);
370 }
371
372 /**
373 * See header
374 */
375 enumerator_t *enumerator_create_nested(enumerator_t *outer,
376 enumerator_t *(inner_constructor)(void *outer, void *data),
377 void *data, void (*destroy_data)(void *data))
378 {
379 nested_enumerator_t *enumerator = malloc_thing(nested_enumerator_t);
380
381 enumerator->public.enumerate = (void*)enumerate_nested;
382 enumerator->public.destroy = (void*)destroy_nested;
383 enumerator->outer = outer;
384 enumerator->inner = NULL;
385 enumerator->create_inner = (void*)inner_constructor;
386 enumerator->data = data;
387 enumerator->destroy_data = destroy_data;
388
389 return &enumerator->public;
390 }
391
392 /**
393 * enumerator for filtered enumerator
394 */
395 typedef struct {
396 enumerator_t public;
397 enumerator_t *unfiltered;
398 void *data;
399 bool (*filter)(void *data, ...);
400 void (*destructor)(void *data);
401 } filter_enumerator_t;
402
403 /**
404 * Implementation of enumerator_create_filter().destroy
405 */
406 static void destroy_filter(filter_enumerator_t *this)
407 {
408 if (this->destructor)
409 {
410 this->destructor(this->data);
411 }
412 this->unfiltered->destroy(this->unfiltered);
413 free(this);
414 }
415
416 /**
417 * Implementation of enumerator_create_filter().enumerate
418 */
419 static bool enumerate_filter(filter_enumerator_t *this, void *o1, void *o2,
420 void *o3, void *o4, void *o5)
421 {
422 void *i1, *i2, *i3, *i4, *i5;
423
424 while (this->unfiltered->enumerate(this->unfiltered, &i1, &i2, &i3, &i4, &i5))
425 {
426 if (this->filter(this->data, &i1, o1, &i2, o2, &i3, o3, &i4, o4, &i5, o5))
427 {
428 return TRUE;
429 }
430 }
431 return FALSE;
432 }
433
434 /**
435 * see header
436 */
437 enumerator_t *enumerator_create_filter(enumerator_t *unfiltered,
438 bool (*filter)(void *data, ...),
439 void *data, void (*destructor)(void *data))
440 {
441 filter_enumerator_t *this = malloc_thing(filter_enumerator_t);
442
443 this->public.enumerate = (void*)enumerate_filter;
444 this->public.destroy = (void*)destroy_filter;
445 this->unfiltered = unfiltered;
446 this->filter = filter;
447 this->data = data;
448 this->destructor = destructor;
449
450 return &this->public;
451 }
452
453 /**
454 * enumerator for cleaner enumerator
455 */
456 typedef struct {
457 enumerator_t public;
458 enumerator_t *wrapped;
459 void (*cleanup)(void *data);
460 void *data;
461 } cleaner_enumerator_t;
462
463 /**
464 * Implementation of enumerator_create_cleanup().destroy
465 */
466 static void destroy_cleaner(cleaner_enumerator_t *this)
467 {
468 this->cleanup(this->data);
469 this->wrapped->destroy(this->wrapped);
470 free(this);
471 }
472
473 /**
474 * Implementation of enumerator_create_cleaner().enumerate
475 */
476 static bool enumerate_cleaner(cleaner_enumerator_t *this, void *v1, void *v2,
477 void *v3, void *v4, void *v5)
478 {
479 return this->wrapped->enumerate(this->wrapped, v1, v2, v3, v4, v5);
480 }
481
482 /**
483 * see header
484 */
485 enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
486 void (*cleanup)(void *data), void *data)
487 {
488 cleaner_enumerator_t *this = malloc_thing(cleaner_enumerator_t);
489
490 this->public.enumerate = (void*)enumerate_cleaner;
491 this->public.destroy = (void*)destroy_cleaner;
492 this->wrapped = wrapped;
493 this->cleanup = cleanup;
494 this->data = data;
495
496 return &this->public;
497 }
498
499 /**
500 * enumerator for single enumerator
501 */
502 typedef struct {
503 enumerator_t public;
504 void *item;
505 void (*cleanup)(void *item);
506 bool done;
507 } single_enumerator_t;
508
509 /**
510 * Implementation of enumerator_create_single().destroy
511 */
512 static void destroy_single(single_enumerator_t *this)
513 {
514 if (this->cleanup)
515 {
516 this->cleanup(this->item);
517 }
518 free(this);
519 }
520
521 /**
522 * Implementation of enumerator_create_single().enumerate
523 */
524 static bool enumerate_single(single_enumerator_t *this, void **item)
525 {
526 if (this->done)
527 {
528 return FALSE;
529 }
530 *item = this->item;
531 this->done = TRUE;
532 return TRUE;
533 }
534
535 /**
536 * see header
537 */
538 enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item))
539 {
540 single_enumerator_t *this = malloc_thing(single_enumerator_t);
541
542 this->public.enumerate = (void*)enumerate_single;
543 this->public.destroy = (void*)destroy_single;
544 this->item = item;
545 this->cleanup = cleanup;
546 this->done = FALSE;
547
548 return &this->public;
549 }
550