/* * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * $Id: enumerator.c 3589 2008-03-13 14:14:44Z martin $ */ #include "enumerator.h" #include #include #include #include #include #include #include /** * Implementation of enumerator_create_empty().enumerate */ static bool enumerate_empty(enumerator_t *enumerator, ...) { return FALSE; } /** * See header */ enumerator_t* enumerator_create_empty() { enumerator_t *this = malloc_thing(enumerator_t); this->enumerate = enumerate_empty; this->destroy = (void*)free; return this; } /** * Enumerator implementation for directory enumerator */ typedef struct { /** implements enumerator_t */ enumerator_t public; /** directory handle */ DIR *dir; /** absolute path of current file */ char full[PATH_MAX]; /** where directory part of full ends and relative file gets written */ char *full_end; } dir_enum_t; /** * Implementation of enumerator_create_directory().destroy */ static void destroy_dir_enum(dir_enum_t *this) { closedir(this->dir); free(this); } /** * Implementation of enumerator_create_directory().enumerate */ static bool enumerate_dir_enum(dir_enum_t *this, char **relative, char **absolute, struct stat *st) { struct dirent *entry = readdir(this->dir); size_t len, remaining; if (!entry) { return FALSE; } if (streq(entry->d_name, ".") || streq(entry->d_name, "..")) { return enumerate_dir_enum(this, relative, absolute, st); } if (relative) { *relative = entry->d_name; } if (absolute || st) { remaining = sizeof(this->full) - (this->full_end - this->full); len = snprintf(this->full_end, remaining, "%s", entry->d_name); if (len < 0 || len >= remaining) { DBG1("buffer too small to enumerate file '%s'", entry->d_name); return FALSE; } if (absolute) { *absolute = this->full; } if (st) { if (stat(this->full, st)) { DBG1("stat() on '%s' failed: %s", this->full, strerror(errno)); return FALSE; } } } return TRUE; } /** * See header */ enumerator_t* enumerator_create_directory(char *path) { size_t len; dir_enum_t *this = malloc_thing(dir_enum_t); this->public.enumerate = (void*)enumerate_dir_enum; this->public.destroy = (void*)destroy_dir_enum; if (*path == '\0') { path = "./"; } len = snprintf(this->full, sizeof(this->full)-1, "%s", path); if (len < 0 || len >= sizeof(this->full)-1) { DBG1("path string %s too long", path); free(this); return NULL; } /* append a '/' if not already done */ if (this->full[len-1] != '/') { this->full[len++] = '/'; this->full[len] = '\0'; } this->full_end = &this->full[len]; this->dir = opendir(path); if (this->dir == NULL) { DBG1("opening directory %s failed: %s", path, strerror(errno)); free(this); return NULL; } return &this->public; } /** * enumerator for nested enumerations */ typedef struct { /* implements enumerator_t */ enumerator_t public; /* outer enumerator */ enumerator_t *outer; /* inner enumerator */ enumerator_t *inner; /* constructor for inner enumerator */ enumerator_t *(*create_inner)(void *outer, void *data); /* data to pass to constructor above */ void *data; /* destructor for data */ void (*destroy_data)(void *data); } nested_enumerator_t; /** * Implementation of enumerator_create_nested().enumerate() */ static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2, void *v3, void *v4, void *v5) { while (TRUE) { while (this->inner == NULL) { void *outer; if (!this->outer->enumerate(this->outer, &outer)) { return FALSE; } this->inner = this->create_inner(outer, this->data); } if (this->inner->enumerate(this->inner, v1, v2, v3, v4, v5)) { return TRUE; } this->inner->destroy(this->inner); this->inner = NULL; } } /** * Implementation of enumerator_create_nested().destroy() **/ static void destroy_nested(nested_enumerator_t *this) { if (this->destroy_data) { this->destroy_data(this->data); } DESTROY_IF(this->inner); this->outer->destroy(this->outer); free(this); } /** * See header */ enumerator_t *enumerator_create_nested(enumerator_t *outer, enumerator_t *(inner_constructor)(void *outer, void *data), void *data, void (*destroy_data)(void *data)) { nested_enumerator_t *enumerator = malloc_thing(nested_enumerator_t); enumerator->public.enumerate = (void*)enumerate_nested; enumerator->public.destroy = (void*)destroy_nested; enumerator->outer = outer; enumerator->inner = NULL; enumerator->create_inner = (void*)inner_constructor; enumerator->data = data; enumerator->destroy_data = destroy_data; return &enumerator->public; } /** * enumerator for filtered enumerator */ typedef struct { enumerator_t public; enumerator_t *unfiltered; void *data; bool (*filter)(void *data, ...); void (*destructor)(void *data); } filter_enumerator_t; /** * Implementation of enumerator_create_filter().destroy */ void destroy_filter(filter_enumerator_t *this) { if (this->destructor) { this->destructor(this->data); } this->unfiltered->destroy(this->unfiltered); free(this); } /** * Implementation of enumerator_create_filter().enumerate */ bool enumerate_filter(filter_enumerator_t *this, void *o1, void *o2, void *o3, void *o4, void *o5) { void *i1, *i2, *i3, *i4, *i5; while (this->unfiltered->enumerate(this->unfiltered, &i1, &i2, &i3, &i4, &i5)) { if (this->filter(this->data, &i1, o1, &i2, o2, &i3, o3, &i4, o4, &i5, o5)) { return TRUE; } } return FALSE; } /** * see header */ enumerator_t *enumerator_create_filter(enumerator_t *unfiltered, bool (*filter)(void *data, ...), void *data, void (*destructor)(void *data)) { filter_enumerator_t *this = malloc_thing(filter_enumerator_t); this->public.enumerate = (void*)enumerate_filter; this->public.destroy = (void*)destroy_filter; this->unfiltered = unfiltered; this->filter = filter; this->data = data; this->destructor = destructor; return &this->public; } /** * enumerator for cleaner enumerator */ typedef struct { enumerator_t public; enumerator_t *wrapped; void (*cleanup)(void *data); void *data; } cleaner_enumerator_t; /** * Implementation of enumerator_create_cleanup().destroy */ static void destroy_cleaner(cleaner_enumerator_t *this) { this->cleanup(this->data); this->wrapped->destroy(this->wrapped); free(this); } /** * Implementation of enumerator_create_cleaner().enumerate */ static bool enumerate_cleaner(cleaner_enumerator_t *this, void *v1, void *v2, void *v3, void *v4, void *v5) { return this->wrapped->enumerate(this->wrapped, v1, v2, v3, v4, v5); } /** * see header */ enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped, void (*cleanup)(void *data), void *data) { cleaner_enumerator_t *this = malloc_thing(cleaner_enumerator_t); this->public.enumerate = (void*)enumerate_cleaner; this->public.destroy = (void*)destroy_cleaner; this->wrapped = wrapped; this->cleanup = cleanup; this->data = data; return &this->public; } /** * enumerator for single enumerator */ typedef struct { enumerator_t public; void *item; void (*cleanup)(void *item); bool done; } single_enumerator_t; /** * Implementation of enumerator_create_single().destroy */ static void destroy_single(single_enumerator_t *this) { if (this->cleanup) { this->cleanup(this->item); } free(this); } /** * Implementation of enumerator_create_single().enumerate */ static bool enumerate_single(single_enumerator_t *this, void **item) { if (this->done) { return FALSE; } *item = this->item; this->done = TRUE; return TRUE; } /** * see header */ enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item)) { single_enumerator_t *this = malloc_thing(single_enumerator_t); this->public.enumerate = (void*)enumerate_single; this->public.destroy = (void*)destroy_single; this->item = item; this->cleanup = cleanup; this->done = FALSE; return &this->public; }