2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2007 Martin Willi
4 * Hochschule fuer Technik Rapperswil
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>.
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
17 #include "enumerator.h"
19 #include <sys/types.h>
31 * Implementation of enumerator_create_empty().enumerate
33 static bool enumerate_empty(enumerator_t
*enumerator
, ...)
41 enumerator_t
* enumerator_create_empty()
43 enumerator_t
*this = malloc_thing(enumerator_t
);
44 this->enumerate
= enumerate_empty
;
45 this->destroy
= (void*)free
;
50 * Enumerator implementation for directory enumerator
53 /** implements enumerator_t */
55 /** directory handle */
57 /** absolute path of current file */
59 /** where directory part of full ends and relative file gets written */
64 * Implementation of enumerator_create_directory().destroy
66 static void destroy_dir_enum(dir_enum_t
*this)
73 * Implementation of enumerator_create_directory().enumerate
75 static bool enumerate_dir_enum(dir_enum_t
*this, char **relative
,
76 char **absolute
, struct stat
*st
)
78 struct dirent
*entry
= readdir(this->dir
);
86 if (streq(entry
->d_name
, ".") || streq(entry
->d_name
, ".."))
88 return enumerate_dir_enum(this, relative
, absolute
, st
);
92 *relative
= entry
->d_name
;
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
)
100 DBG1(DBG_LIB
, "buffer too small to enumerate file '%s'",
106 *absolute
= this->full
;
110 if (stat(this->full
, st
))
112 DBG1(DBG_LIB
, "stat() on '%s' failed: %s", this->full
,
124 enumerator_t
* enumerator_create_directory(const char *path
)
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
;
135 len
= snprintf(this->full
, sizeof(this->full
)-1, "%s", path
);
136 if (len
< 0 || len
>= sizeof(this->full
)-1)
138 DBG1(DBG_LIB
, "path string '%s' too long", path
);
142 /* append a '/' if not already done */
143 if (this->full
[len
-1] != '/')
145 this->full
[len
++] = '/';
146 this->full
[len
] = '\0';
148 this->full_end
= &this->full
[len
];
150 this->dir
= opendir(path
);
151 if (this->dir
== NULL
)
153 DBG1(DBG_LIB
, "opening directory '%s' failed: %s", path
, strerror(errno
));
157 return &this->public;
161 * Enumerator implementation for directory enumerator
164 /** implements enumerator_t */
166 /** string to parse */
168 /** current position */
170 /** separater chars */
177 * Implementation of enumerator_create_token().destroy
179 static void destroy_token_enum(token_enum_t
*this)
186 * Implementation of enumerator_create_token().enumerate
188 static bool enumerate_token_enum(token_enum_t
*this, char **token
)
190 const char *sep
, *trim
;
191 char *pos
= NULL
, *tmp
;
194 /* trim leading characters/separators */
200 if (*trim
== *this->pos
)
210 if (*sep
== *this->pos
)
228 /* read quoted token */
229 tmp
= strchr(this->pos
+ 1, *this->pos
);
232 *token
= this->pos
+ 1;
237 /* unterminated string, FALL-THROUGH */
241 /* find nearest separator */
245 tmp
= strchr(this->pos
, *sep
);
246 if (tmp
&& (pos
== NULL
|| tmp
< pos
))
261 pos
= this->pos
= strchr(this->pos
, '\0');
267 /* trim trailing characters/separators */
269 while (pos
>= *token
)
297 if (!last
|| pos
>= *token
)
307 enumerator_t
* enumerator_create_token(const char *string
, const char *sep
,
310 token_enum_t
*enumerator
= malloc_thing(token_enum_t
);
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
;
319 return &enumerator
->public;
323 * enumerator for nested enumerations
326 /* implements enumerator_t */
328 /* outer enumerator */
330 /* inner enumerator */
332 /* constructor for inner enumerator */
333 enumerator_t
*(*create_inner
)(void *outer
, void *data
);
334 /* data to pass to constructor above */
336 /* destructor for data */
337 void (*destroy_data
)(void *data
);
338 } nested_enumerator_t
;
342 * Implementation of enumerator_create_nested().enumerate()
344 static bool enumerate_nested(nested_enumerator_t
*this, void *v1
, void *v2
,
345 void *v3
, void *v4
, void *v5
)
349 while (this->inner
== NULL
)
353 if (!this->outer
->enumerate(this->outer
, &outer
))
357 this->inner
= this->create_inner(outer
, this->data
);
359 if (this->inner
->enumerate(this->inner
, v1
, v2
, v3
, v4
, v5
))
363 this->inner
->destroy(this->inner
);
369 * Implementation of enumerator_create_nested().destroy()
371 static void destroy_nested(nested_enumerator_t
*this)
373 if (this->destroy_data
)
375 this->destroy_data(this->data
);
377 DESTROY_IF(this->inner
);
378 this->outer
->destroy(this->outer
);
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
))
389 nested_enumerator_t
*enumerator
= malloc_thing(nested_enumerator_t
);
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
;
399 return &enumerator
->public;
403 * enumerator for filtered enumerator
407 enumerator_t
*unfiltered
;
409 bool (*filter
)(void *data
, ...);
410 void (*destructor
)(void *data
);
411 } filter_enumerator_t
;
414 * Implementation of enumerator_create_filter().destroy
416 static void destroy_filter(filter_enumerator_t
*this)
418 if (this->destructor
)
420 this->destructor(this->data
);
422 this->unfiltered
->destroy(this->unfiltered
);
427 * Implementation of enumerator_create_filter().enumerate
429 static bool enumerate_filter(filter_enumerator_t
*this, void *o1
, void *o2
,
430 void *o3
, void *o4
, void *o5
)
432 void *i1
, *i2
, *i3
, *i4
, *i5
;
434 while (this->unfiltered
->enumerate(this->unfiltered
, &i1
, &i2
, &i3
, &i4
, &i5
))
436 if (this->filter(this->data
, &i1
, o1
, &i2
, o2
, &i3
, o3
, &i4
, o4
, &i5
, o5
))
447 enumerator_t
*enumerator_create_filter(enumerator_t
*unfiltered
,
448 bool (*filter
)(void *data
, ...),
449 void *data
, void (*destructor
)(void *data
))
451 filter_enumerator_t
*this = malloc_thing(filter_enumerator_t
);
453 this->public.enumerate
= (void*)enumerate_filter
;
454 this->public.destroy
= (void*)destroy_filter
;
455 this->unfiltered
= unfiltered
;
456 this->filter
= filter
;
458 this->destructor
= destructor
;
460 return &this->public;
464 * enumerator for cleaner enumerator
468 enumerator_t
*wrapped
;
469 void (*cleanup
)(void *data
);
471 } cleaner_enumerator_t
;
474 * Implementation of enumerator_create_cleanup().destroy
476 static void destroy_cleaner(cleaner_enumerator_t
*this)
478 this->cleanup(this->data
);
479 this->wrapped
->destroy(this->wrapped
);
484 * Implementation of enumerator_create_cleaner().enumerate
486 static bool enumerate_cleaner(cleaner_enumerator_t
*this, void *v1
, void *v2
,
487 void *v3
, void *v4
, void *v5
)
489 return this->wrapped
->enumerate(this->wrapped
, v1
, v2
, v3
, v4
, v5
);
495 enumerator_t
*enumerator_create_cleaner(enumerator_t
*wrapped
,
496 void (*cleanup
)(void *data
), void *data
)
498 cleaner_enumerator_t
*this = malloc_thing(cleaner_enumerator_t
);
500 this->public.enumerate
= (void*)enumerate_cleaner
;
501 this->public.destroy
= (void*)destroy_cleaner
;
502 this->wrapped
= wrapped
;
503 this->cleanup
= cleanup
;
506 return &this->public;
510 * enumerator for single enumerator
515 void (*cleanup
)(void *item
);
517 } single_enumerator_t
;
520 * Implementation of enumerator_create_single().destroy
522 static void destroy_single(single_enumerator_t
*this)
526 this->cleanup(this->item
);
532 * Implementation of enumerator_create_single().enumerate
534 static bool enumerate_single(single_enumerator_t
*this, void **item
)
548 enumerator_t
*enumerator_create_single(void *item
, void (*cleanup
)(void *item
))
550 single_enumerator_t
*this = malloc_thing(single_enumerator_t
);
552 this->public.enumerate
= (void*)enumerate_single
;
553 this->public.destroy
= (void*)destroy_single
;
555 this->cleanup
= cleanup
;
558 return &this->public;