diff --git a/libc/Makefile b/libc/Makefile index 0ed6937c..6de9caf8 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -182,6 +182,7 @@ $(CPUDIR)/signal.o \ $(CPUDIR)/syscall.o \ creat.o \ dirent/fddir-sortix.o \ +dirent/scandir.o \ dirname.o \ dispmsg_issue.o \ dlfcn.o \ diff --git a/libc/dirent/scandir.cpp b/libc/dirent/scandir.cpp new file mode 100644 index 00000000..e538a1dd --- /dev/null +++ b/libc/dirent/scandir.cpp @@ -0,0 +1,87 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2013. + + This file is part of the Sortix C Library. + + The Sortix C Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at your + option) any later version. + + The Sortix C Library 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 Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with the Sortix C Library. If not, see . + + dirent/scandir.cpp + Filtered and sorted directory reading. + +*******************************************************************************/ + +#include +#include +#include +#include +#include + +extern "C" +int scandir(const char* path, struct dirent*** namelist_ptr, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)) +{ + DIR* dir = opendir(path); + if ( !dir ) + return -1; + + size_t namelist_used = 0; + size_t namelist_length = 0; + struct dirent** namelist = NULL; + + if ( false ) + { + out_error: + for ( size_t i = 0; i < namelist_used; i++ ) + free(namelist[i]); + free(namelist); + closedir(dir); + return errno = EOVERFLOW, -1; + } + + while ( struct dirent* entry = readdir(dir) ) + { + if ( filter && !filter(entry) ) + continue; + if ( (size_t) INT_MAX <= namelist_used ) + goto out_error; + if ( namelist_used == namelist_length ) + { + size_t new_length = namelist_length ? 2 * namelist_length : 8; + size_t new_size = new_length * sizeof(struct dirent*); + struct dirent** list = (struct dirent**) realloc(namelist, new_size); + if ( !list ) + goto out_error; + namelist = list; + namelist_length = new_length; + } + size_t name_length = strlen(entry->d_name); + size_t dirent_size = sizeof(struct dirent) + name_length + 1; + struct dirent* dirent = (struct dirent*) malloc(dirent_size); + if ( !dirent_size ) + goto out_error; + memcpy(dirent, entry, sizeof(*entry)); + strcpy(dirent->d_name, entry->d_name); + namelist[namelist_used++] = dirent; + } + + if ( compare ) + qsort(namelist, namelist_used, sizeof(struct dirent*), + (int (*)(const void*, const void*)) compare); + + closedir(dir); + + return *namelist_ptr = namelist, (int) namelist_used; +} diff --git a/libc/include/dirent.h b/libc/include/dirent.h index 4468e05b..d52002fe 100644 --- a/libc/include/dirent.h +++ b/libc/include/dirent.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. This file is part of the Sortix C Library. @@ -22,8 +22,8 @@ *******************************************************************************/ -#ifndef _DIRENT_H -#define _DIRENT_H 1 +#ifndef INCLUDE_DIRENT_H +#define INCLUDE_DIRENT_H #include @@ -46,6 +46,8 @@ DIR* fdopendir(int fd); DIR* opendir(const char* path); struct dirent* readdir(DIR* dir); void rewinddir(DIR* dir); +int scandir(const char*, struct dirent***, int (*)(const struct dirent*), + int (*)(const struct dirent**, const struct dirent**)); #if defined(_SORTIX_SOURCE) void dregister(DIR* dir);