Mercurial > molko
diff libmlk-util/mlk/util/dir.c @ 570:aaf518c87628
util: introduce dir module
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 09 Mar 2023 20:30:00 +0100 |
parents | |
children | cba66f7d8a53 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-util/mlk/util/dir.c Thu Mar 09 20:30:00 2023 +0100 @@ -0,0 +1,153 @@ +/* + * dir.c -- portable directory iterator + * + * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include "dir.h" +#include "sysconfig.h" + +#if defined(MLK_HAVE_DIRENT_H) + +/* {{{ Generic dirent.h support. */ + +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +struct self { + DIR *dp; + struct dirent *entry; +}; + +static inline int +skip(const struct self *self) +{ + return strcmp(self->entry->d_name, ".") == 0 || + strcmp(self->entry->d_name, "..") == 0; +} + +static void +handle_finish(struct mlk_dir_iter *iter) +{ + struct self *self = iter->handle; + + if (self) { + closedir(self->dp); + free(self); + } + + iter->entry = NULL; + iter->handle = NULL; +} + +static int +handle_open(struct mlk_dir_iter *iter, const char *path) +{ + struct self *self; + + if (!(self = calloc(1, sizeof (*self)))) + return -1; + if (!(self->dp = opendir(path))) { + free(self); + return -1; + } + + iter->handle = self; + + return 0; +} + +static int +handle_next(struct mlk_dir_iter *iter) +{ + struct self *self = iter->handle; + + /* Skip . and .. which are barely useful. */ + while ((self->entry = readdir(self->dp)) && skip(self)) + continue; + + /* End of directory, free all and indicate EOF to the user. */ + if (!self->entry) { + handle_finish(iter); + return 0; + } + + iter->entry = self->entry->d_name; + + return 1; +} + +/* }}} */ + +#else + +/* {{{ No-op implementation */ + +#include <stddef.h> + +int +handle_open(struct mlk_dir_iter *iter, const char *path) +{ + (void)path; + + iter->entry = NULL; + iter->handle = NULL; + + return -1; +} + +int +handle_next(struct mlk_dir_iter *iter) +{ + (void)iter; + + return 0; +} + +void +handle_finish(struct mlk_dir_iter *iter) +{ + (void)iter; +} + +/* }}} */ + +#endif + +int +mlk_dir_open(struct mlk_dir_iter *iter, const char *path) +{ + assert(path); + + return handle_open(iter, path); +} + +int +mlk_dir_next(struct mlk_dir_iter *iter) +{ + assert(iter); + + return handle_next(iter); +} + +void +mlk_dir_finish(struct mlk_dir_iter *iter) +{ + return handle_finish(iter); +}