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