Mercurial > molko
view libmlk-util/mlk/util/dir.c @ 599:cb8ca73f1aa4
rpg: walksprite -> mlk_walksprite
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 31 Mar 2023 20:01:00 +0200 |
parents | f937857336f3 |
children |
line wrap: on
line source
/* * 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) { 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, 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) { 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; } /* }}} */ #elif defined(_WIN32) /* {{{ Native Windows implementation. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <windows.h> struct self { WIN32_FIND_DATA data; HANDLE handle; int cached; }; static inline int skip(const struct self *self) { return strcmp(self->data.cFileName, ".") == 0 || strcmp(self->data.cFileName, "..") == 0; } static void handle_finish(struct mlk_dir *iter) { struct self *self = iter->handle; if (self) { FindClose(self->handle); free(self); } iter->entry = NULL; iter->handle = NULL; } static int handle_open(struct mlk_dir *iter, const char *path) { struct self *self; char directory[MAX_PATH]; BOOL ret = TRUE; snprintf(directory, sizeof (directory), "%s\\*", path); if (!(self = calloc(1, sizeof (*self)))) return -1; if ((self->handle = FindFirstFileA(directory, &self->data)) == INVALID_HANDLE_VALUE) { free(self); return -1; } /* Skip . and .. */ while (skip(self) && (ret = FindNextFileA(self->handle, &self->data))) continue; /* Something failed. */ if (!ret) { handle_finish(iter); return -1; } self->cached = 1; iter->entry = self->data.cFileName; iter->handle = self; return 0; } static int handle_next(struct mlk_dir *iter) { struct self *self = iter->handle; BOOL ret = TRUE; /* Returning the first entry on open. */ if (self->cached) self->cached = 0; else { /* The . and .. can still appear now. */ while ((ret = FindNextFileA(self->handle, &self->data)) && skip(self)) continue; if (!ret) handle_finish(iter); } return iter->entry != NULL; } /* }}} */ #else /* {{{ No-op implementation */ #include <stddef.h> static int handle_open(struct mlk_dir *iter, const char *path) { (void)path; iter->entry = NULL; iter->handle = NULL; return -1; } static int handle_next(struct mlk_dir *iter) { (void)iter; return 0; } static void handle_finish(struct mlk_dir *iter) { (void)iter; } /* }}} */ #endif int mlk_dir_open(struct mlk_dir *iter, const char *path) { assert(path); iter->entry = NULL; iter->handle = NULL; return handle_open(iter, path); } int mlk_dir_next(struct mlk_dir *iter) { assert(iter); return handle_next(iter); } void mlk_dir_finish(struct mlk_dir *iter) { handle_finish(iter); }